1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

gitlab_user: add support for identity provider (#2691) (#2852)

* Add identity functionality

* Add functionality for user without provider or extern_uid

* Fix missing key error and documentation

* Fix failing tests

* Update docs

* Add changelog fragment

* Update plugins/modules/source_control/gitlab/gitlab_user.py

Add version

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/source_control/gitlab/gitlab_user.py

Update boolean default

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/source_control/gitlab/gitlab_user.py

Fix syntax

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/source_control/gitlab/gitlab_user.py

Remove no_log

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update changelogs/fragments/2691-gitlab_user-support-identity-provider.yml

Update syntax

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/source_control/gitlab/gitlab_user.py

Update syntax

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update docs

* Add functionality to add multiple identities at once

* Fix identity example

* Add suboptions

* Add elements

* Update plugins/modules/source_control/gitlab/gitlab_user.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Apply comma's at the end of dictionaries

Co-authored-by: Felix Fontein <felix@fontein.de>

* Add check mode

* Change checkmode for user add and identity delete

* Update plugins/modules/source_control/gitlab/gitlab_user.py

* Update changelogs/fragments/2691-gitlab_user-support-identity-provider.yml

Add more features to changelog as suggested here https://github.com/ansible-collections/community.general/pull/2691#discussion_r653250717

Co-authored-by: Felix Fontein <felix@fontein.de>

* Add better description for identities list and overwrite_identities boolean

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: lennert.mertens <lennert.mertens@nubera.eu>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: stef.graces <stef.graces@nubera.eu>
Co-authored-by: Stef Graces <stefgraces@hotmail.com>
Co-authored-by: Stef Graces <sgraces@sofico.be>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit d6d0b6f0c1)

Co-authored-by: Lennert Mertens <lennert.mertens@gmail.com>
This commit is contained in:
patchback[bot] 2021-06-21 21:55:34 +02:00 committed by GitHub
parent 20bda07aaf
commit feb1c1081e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 123 additions and 4 deletions

View file

@ -0,0 +1,5 @@
---
minor_changes:
- "gitlab_user - specifying a password is no longer necessary (https://github.com/ansible-collections/community.general/pull/2691)."
- "gitlab_user - allow to reset an existing password with the new ``reset_password`` option (https://github.com/ansible-collections/community.general/pull/2691)."
- "gitlab_user - add functionality for adding external identity providers to a GitLab user (https://github.com/ansible-collections/community.general/pull/2691)."

View file

@ -1,6 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright: (c) 2021, Lennert Mertens (lennert@nubera.be)
# Copyright: (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr) # Copyright: (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
# Copyright: (c) 2015, Werner Dijkerman (ikben@werner-dijkerman.nl) # Copyright: (c) 2015, Werner Dijkerman (ikben@werner-dijkerman.nl)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@ -22,6 +23,8 @@ notes:
author: author:
- Werner Dijkerman (@dj-wasabi) - Werner Dijkerman (@dj-wasabi)
- Guillaume Martinez (@Lunik) - Guillaume Martinez (@Lunik)
- Lennert Mertens (@LennertMertens)
- Stef Graces (@stgrace)
requirements: requirements:
- python >= 2.7 - python >= 2.7
- python-gitlab python module - python-gitlab python module
@ -50,6 +53,12 @@ options:
- GitLab server enforces minimum password length to 8, set this value with 8 or more characters. - GitLab server enforces minimum password length to 8, set this value with 8 or more characters.
- Required only if C(state) is set to C(present). - Required only if C(state) is set to C(present).
type: str type: str
reset_password:
description:
- Whether the user can change its password or not.
default: false
type: bool
version_added: 3.3.0
email: email:
description: description:
- The email that belongs to the user. - The email that belongs to the user.
@ -107,6 +116,30 @@ options:
- Define external parameter for this user. - Define external parameter for this user.
type: bool type: bool
default: no default: no
identities:
description:
- List of identities to be added/updated for this user.
- To remove all other identities from this user, set I(overwrite_identities=true).
type: list
elements: dict
suboptions:
provider:
description:
- The name of the external identity provider
type: str
extern_uid:
description:
- User ID for external identity.
type: str
version_added: 3.3.0
overwrite_identities:
description:
- Overwrite identities with identities added in this module.
- This means that all identities that the user has and that are not listed in I(identities) are removed from the user.
- This is only done if a list is provided for I(identities). To remove all identities, provide an empty list.
type: bool
default: false
version_added: 3.3.0
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -134,6 +167,22 @@ EXAMPLES = '''
group: super_group/mon_group group: super_group/mon_group
access_level: owner access_level: owner
- name: "Create GitLab User using external identity provider"
community.general.gitlab_user:
api_url: https://gitlab.example.com/
validate_certs: True
api_token: "{{ access_token }}"
name: My Name
username: myusername
password: mysecretpassword
email: me@example.com
identities:
- provider: Keycloak
extern_uid: f278f95c-12c7-4d51-996f-758cc2eb11bc
state: present
group: super_group/mon_group
access_level: owner
- name: "Block GitLab User" - name: "Block GitLab User"
community.general.gitlab_user: community.general.gitlab_user:
api_url: https://gitlab.example.com/ api_url: https://gitlab.example.com/
@ -219,10 +268,13 @@ class GitLabUser(object):
'name': options['name'], 'name': options['name'],
'username': username, 'username': username,
'password': options['password'], 'password': options['password'],
'reset_password': options['reset_password'],
'email': options['email'], 'email': options['email'],
'skip_confirmation': not options['confirm'], 'skip_confirmation': not options['confirm'],
'admin': options['isadmin'], 'admin': options['isadmin'],
'external': options['external']}) 'external': options['external'],
'identities': options['identities'],
})
changed = True changed = True
else: else:
changed, user = self.updateUser( changed, user = self.updateUser(
@ -240,6 +292,7 @@ class GitLabUser(object):
'value': options['isadmin'], 'setter': 'admin' 'value': options['isadmin'], 'setter': 'admin'
}, },
'external': {'value': options['external']}, 'external': {'value': options['external']},
'identities': {'value': options['identities']},
}, },
{ {
# put "uncheckable" params here, this means params # put "uncheckable" params here, this means params
@ -247,6 +300,8 @@ class GitLabUser(object):
# not return any information about it # not return any information about it
'skip_reconfirmation': {'value': not options['confirm']}, 'skip_reconfirmation': {'value': not options['confirm']},
'password': {'value': options['password']}, 'password': {'value': options['password']},
'reset_password': {'value': options['reset_password']},
'overwrite_identities': {'value': options['overwrite_identities']},
} }
) )
@ -393,7 +448,10 @@ class GitLabUser(object):
av = arg_value['value'] av = arg_value['value']
if av is not None: if av is not None:
if getattr(user, arg_key) != av: if arg_key == "identities":
changed = self.addIdentities(user, av, uncheckable_args['overwrite_identities']['value'])
elif getattr(user, arg_key) != av:
setattr(user, arg_value.get('setter', arg_key), av) setattr(user, arg_value.get('setter', arg_key), av)
changed = True changed = True
@ -412,13 +470,53 @@ class GitLabUser(object):
if self._module.check_mode: if self._module.check_mode:
return True return True
identities = None
if 'identities' in arguments:
identities = arguments['identities']
del arguments['identities']
try: try:
user = self._gitlab.users.create(arguments) user = self._gitlab.users.create(arguments)
if identities:
self.addIdentities(user, identities)
except (gitlab.exceptions.GitlabCreateError) as e: except (gitlab.exceptions.GitlabCreateError) as e:
self._module.fail_json(msg="Failed to create user: %s " % to_native(e)) self._module.fail_json(msg="Failed to create user: %s " % to_native(e))
return user return user
'''
@param user User object
@param identites List of identities to be added/updated
@param overwrite_identities Overwrite user identities with identities passed to this module
'''
def addIdentities(self, user, identities, overwrite_identities=False):
changed = False
if overwrite_identities:
changed = self.deleteIdentities(user, identities)
for identity in identities:
if identity not in user.identities:
setattr(user, 'provider', identity['provider'])
setattr(user, 'extern_uid', identity['extern_uid'])
if not self._module.check_mode:
user.save()
changed = True
return changed
'''
@param user User object
@param identites List of identities to be added/updated
'''
def deleteIdentities(self, user, identities):
changed = False
for identity in user.identities:
if identity not in identities:
if not self._module.check_mode:
user.identityproviders.delete(identity['provider'])
changed = True
return changed
''' '''
@param username Username of the user @param username Username of the user
''' '''
@ -471,6 +569,13 @@ class GitLabUser(object):
return user.unblock() return user.unblock()
def sanitize_arguments(arguments):
for key, value in list(arguments.items()):
if value is None:
del arguments[key]
return arguments
def main(): def main():
argument_spec = basic_auth_argument_spec() argument_spec = basic_auth_argument_spec()
argument_spec.update(dict( argument_spec.update(dict(
@ -479,6 +584,7 @@ def main():
state=dict(type='str', default="present", choices=["absent", "present", "blocked", "unblocked"]), state=dict(type='str', default="present", choices=["absent", "present", "blocked", "unblocked"]),
username=dict(type='str', required=True), username=dict(type='str', required=True),
password=dict(type='str', no_log=True), password=dict(type='str', no_log=True),
reset_password=dict(type='bool', default=False, no_log=False),
email=dict(type='str'), email=dict(type='str'),
sshkey_name=dict(type='str'), sshkey_name=dict(type='str'),
sshkey_file=dict(type='str', no_log=False), sshkey_file=dict(type='str', no_log=False),
@ -488,6 +594,8 @@ def main():
confirm=dict(type='bool', default=True), confirm=dict(type='bool', default=True),
isadmin=dict(type='bool', default=False), isadmin=dict(type='bool', default=False),
external=dict(type='bool', default=False), external=dict(type='bool', default=False),
identities=dict(type='list', elements='dict'),
overwrite_identities=dict(type='bool', default=False),
)) ))
module = AnsibleModule( module = AnsibleModule(
@ -504,7 +612,7 @@ def main():
], ],
supports_check_mode=True, supports_check_mode=True,
required_if=( required_if=(
('state', 'present', ['name', 'email', 'password']), ('state', 'present', ['name', 'email']),
) )
) )
@ -512,6 +620,7 @@ def main():
state = module.params['state'] state = module.params['state']
user_username = module.params['username'].lower() user_username = module.params['username'].lower()
user_password = module.params['password'] user_password = module.params['password']
user_reset_password = module.params['reset_password']
user_email = module.params['email'] user_email = module.params['email']
user_sshkey_name = module.params['sshkey_name'] user_sshkey_name = module.params['sshkey_name']
user_sshkey_file = module.params['sshkey_file'] user_sshkey_file = module.params['sshkey_file']
@ -521,6 +630,8 @@ def main():
confirm = module.params['confirm'] confirm = module.params['confirm']
user_isadmin = module.params['isadmin'] user_isadmin = module.params['isadmin']
user_external = module.params['external'] user_external = module.params['external']
user_identities = module.params['identities']
overwrite_identities = module.params['overwrite_identities']
if not HAS_GITLAB_PACKAGE: if not HAS_GITLAB_PACKAGE:
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR) module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
@ -559,6 +670,7 @@ def main():
if gitlab_user.createOrUpdateUser(user_username, { if gitlab_user.createOrUpdateUser(user_username, {
"name": user_name, "name": user_name,
"password": user_password, "password": user_password,
"reset_password": user_reset_password,
"email": user_email, "email": user_email,
"sshkey_name": user_sshkey_name, "sshkey_name": user_sshkey_name,
"sshkey_file": user_sshkey_file, "sshkey_file": user_sshkey_file,
@ -567,7 +679,9 @@ def main():
"access_level": access_level, "access_level": access_level,
"confirm": confirm, "confirm": confirm,
"isadmin": user_isadmin, "isadmin": user_isadmin,
"external": user_external}): "external": user_external,
"identities": user_identities,
"overwrite_identities": overwrite_identities}):
module.exit_json(changed=True, msg="Successfully created or updated the user %s" % user_username, user=gitlab_user.userObject._attrs) module.exit_json(changed=True, msg="Successfully created or updated the user %s" % user_username, user=gitlab_user.userObject._attrs)
else: else:
module.exit_json(changed=False, msg="No need to update the user %s" % user_username, user=gitlab_user.userObject._attrs) module.exit_json(changed=False, msg="No need to update the user %s" % user_username, user=gitlab_user.userObject._attrs)