mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
New Module: Keycloak User Rolemapping (#4898)
* keycloak_user_rolemapping: implement user role mapping * keycloak_user_rolemapping: additional logging * keycloak_user_rolemapping: move to getters, use names parameters * keycloak_user_rolemapping: add service account user example * Add keyring and keyring_info modules (#4764) * keycloak_user_rolemapping: write tests, address ansibullbot concerns no.1 * keycloak_user_rolemapping: address felixfontein concerns no.1 * keycloak_user_rolemapping: remove rebase mistakes * keycloak_user_rolemapping: address felixfontein concerns no.2 * keycloak_user_rolemapping: refactor duplicate username usage example * keycloak_user_rolemapping: fix sanity check errors no.1 * keycloak_user_rolemapping: fix sanity check errors no.2 * keycloak_user_rolemapping: fix sanity check errors no.3 * keycloak_user_rolemapping: fix sanity check errors no.4 * keycloak_user_rolemapping: write tests, address ansibullbot concerns no.1 * keycloak_user_rolemapping: resolve rebase conflicts with origin/main branch # Conflicts: # plugins/module_utils/identity/keycloak/keycloak.py * keycloak_user_rolemapping: remove keycloak_role_composites from BOTMETA.yml * keycloak_user_rolemapping: fix sanity check errors no.5 * keycloak_user_rolemapping: address felixfontein reviews concerns no.1 * keycloak_user_rolemapping: address felixfontein reviews concerns no.2 Co-authored-by: Dušan Markovič <dusan.markovic@better.care> Co-authored-by: ahussey-redhat <93101976+ahussey-redhat@users.noreply.github.com>
This commit is contained in:
parent
2eba5dc4e7
commit
2cac3ae879
9 changed files with 916 additions and 90 deletions
2
.github/BOTMETA.yml
vendored
2
.github/BOTMETA.yml
vendored
|
@ -589,6 +589,8 @@ files:
|
|||
maintainers: Gaetan2907
|
||||
$modules/identity/keycloak/keycloak_client_rolemapping.py:
|
||||
maintainers: Gaetan2907
|
||||
$modules/identity/keycloak/keycloak_user_rolemapping.py:
|
||||
maintainers: bratwurzt
|
||||
$modules/identity/keycloak/keycloak_group.py:
|
||||
maintainers: adamgoossens
|
||||
$modules/identity/keycloak/keycloak_identity_provider.py:
|
||||
|
|
|
@ -612,6 +612,8 @@ plugin_routing:
|
|||
redirect: community.general.identity.keycloak.keycloak_role
|
||||
keycloak_user_federation:
|
||||
redirect: community.general.identity.keycloak.keycloak_user_federation
|
||||
keycloak_user_rolemapping:
|
||||
redirect: community.general.identity.keycloak.keycloak_user_rolemapping
|
||||
keyring:
|
||||
redirect: community.general.system.keyring
|
||||
keyring_info:
|
||||
|
|
|
@ -29,8 +29,15 @@ URL_CLIENT_ROLE_COMPOSITES = "{url}/admin/realms/{realm}/clients/{id}/roles/{nam
|
|||
|
||||
URL_REALM_ROLES = "{url}/admin/realms/{realm}/roles"
|
||||
URL_REALM_ROLE = "{url}/admin/realms/{realm}/roles/{name}"
|
||||
URL_REALM_ROLEMAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/realm"
|
||||
URL_REALM_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/users/{id}/role-mappings/realm/available"
|
||||
URL_REALM_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/users/{id}/role-mappings/realm/composite"
|
||||
URL_REALM_ROLE_COMPOSITES = "{url}/admin/realms/{realm}/roles/{name}/composites"
|
||||
|
||||
URL_ROLES_BY_ID = "{url}/admin/realms/{realm}/roles-by-id/{id}"
|
||||
URL_ROLES_BY_ID_COMPOSITES_CLIENTS = "{url}/admin/realms/{realm}/roles-by-id/{id}/composites/clients/{cid}"
|
||||
URL_ROLES_BY_ID_COMPOSITES = "{url}/admin/realms/{realm}/roles-by-id/{id}/composites"
|
||||
|
||||
URL_CLIENTTEMPLATE = "{url}/admin/realms/{realm}/client-templates/{id}"
|
||||
URL_CLIENTTEMPLATES = "{url}/admin/realms/{realm}/client-templates"
|
||||
URL_GROUPS = "{url}/admin/realms/{realm}/groups"
|
||||
|
@ -41,9 +48,15 @@ URL_CLIENTSCOPE = "{url}/admin/realms/{realm}/client-scopes/{id}"
|
|||
URL_CLIENTSCOPE_PROTOCOLMAPPERS = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models"
|
||||
URL_CLIENTSCOPE_PROTOCOLMAPPER = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models/{mapper_id}"
|
||||
|
||||
URL_CLIENT_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}"
|
||||
URL_CLIENT_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/available"
|
||||
URL_CLIENT_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/composite"
|
||||
URL_CLIENT_GROUP_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}"
|
||||
URL_CLIENT_GROUP_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/available"
|
||||
URL_CLIENT_GROUP_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/composite"
|
||||
|
||||
URL_USERS = "{url}/admin/realms/{realm}/users"
|
||||
URL_CLIENT_SERVICE_ACCOUNT_USER = "{url}/admin/realms/{realm}/clients/{id}/service-account-user"
|
||||
URL_CLIENT_USER_ROLEMAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}"
|
||||
URL_CLIENT_USER_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}/available"
|
||||
URL_CLIENT_USER_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}/composite"
|
||||
|
||||
URL_AUTHENTICATION_FLOWS = "{url}/admin/realms/{realm}/authentication/flows"
|
||||
URL_AUTHENTICATION_FLOW = "{url}/admin/realms/{realm}/authentication/flows/{id}"
|
||||
|
@ -446,10 +459,9 @@ class KeycloakAPI(object):
|
|||
self.module.fail_json(msg="Could not fetch rolemappings for client %s in realm %s: %s"
|
||||
% (cid, realm, str(e)))
|
||||
|
||||
def get_client_role_by_name(self, gid, cid, name, realm="master"):
|
||||
def get_client_role_id_by_name(self, cid, name, realm="master"):
|
||||
""" Get the role ID of a client.
|
||||
|
||||
:param gid: ID of the group from which to obtain the rolemappings.
|
||||
:param cid: ID of the client from which to obtain the rolemappings.
|
||||
:param name: Name of the role.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
|
@ -461,7 +473,7 @@ class KeycloakAPI(object):
|
|||
return role['id']
|
||||
return None
|
||||
|
||||
def get_client_rolemapping_by_id(self, gid, cid, rid, realm='master'):
|
||||
def get_client_group_rolemapping_by_id(self, gid, cid, rid, realm='master'):
|
||||
""" Obtain client representation by id
|
||||
|
||||
:param gid: ID of the group from which to obtain the rolemappings.
|
||||
|
@ -470,7 +482,7 @@ class KeycloakAPI(object):
|
|||
:param realm: client from this realm
|
||||
:return: dict of rolemapping representation or None if none matching exist
|
||||
"""
|
||||
rolemappings_url = URL_CLIENT_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
rolemappings_url = URL_CLIENT_GROUP_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
try:
|
||||
rolemappings = json.loads(to_native(open_url(rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
|
@ -483,7 +495,7 @@ class KeycloakAPI(object):
|
|||
% (cid, gid, realm, str(e)))
|
||||
return None
|
||||
|
||||
def get_client_available_rolemappings(self, gid, cid, realm="master"):
|
||||
def get_client_group_available_rolemappings(self, gid, cid, realm="master"):
|
||||
""" Fetch the available role of a client in a specified goup on the Keycloak server.
|
||||
|
||||
:param gid: ID of the group from which to obtain the rolemappings.
|
||||
|
@ -491,7 +503,7 @@ class KeycloakAPI(object):
|
|||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: The rollemappings of specified group and client of the realm (default "master").
|
||||
"""
|
||||
available_rolemappings_url = URL_CLIENT_ROLEMAPPINGS_AVAILABLE.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
available_rolemappings_url = URL_CLIENT_GROUP_ROLEMAPPINGS_AVAILABLE.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(available_rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
|
@ -500,7 +512,7 @@ class KeycloakAPI(object):
|
|||
self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
|
||||
% (cid, gid, realm, str(e)))
|
||||
|
||||
def get_client_composite_rolemappings(self, gid, cid, realm="master"):
|
||||
def get_client_group_composite_rolemappings(self, gid, cid, realm="master"):
|
||||
""" Fetch the composite role of a client in a specified group on the Keycloak server.
|
||||
|
||||
:param gid: ID of the group from which to obtain the rolemappings.
|
||||
|
@ -508,15 +520,64 @@ class KeycloakAPI(object):
|
|||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: The rollemappings of specified group and client of the realm (default "master").
|
||||
"""
|
||||
available_rolemappings_url = URL_CLIENT_ROLEMAPPINGS_COMPOSITE.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
composite_rolemappings_url = URL_CLIENT_GROUP_ROLEMAPPINGS_COMPOSITE.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(available_rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
return json.loads(to_native(open_url(composite_rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
|
||||
% (cid, gid, realm, str(e)))
|
||||
|
||||
def get_role_by_id(self, rid, realm="master"):
|
||||
""" Fetch a role by its id on the Keycloak server.
|
||||
|
||||
:param rid: ID of the role.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: The role.
|
||||
"""
|
||||
client_roles_url = URL_ROLES_BY_ID.format(url=self.baseurl, realm=realm, id=rid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(client_roles_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch role for id %s in realm %s: %s"
|
||||
% (rid, realm, str(e)))
|
||||
|
||||
def get_client_roles_by_id_composite_rolemappings(self, rid, cid, realm="master"):
|
||||
""" Fetch a role by its id on the Keycloak server.
|
||||
|
||||
:param rid: ID of the composite role.
|
||||
:param cid: ID of the client from which to obtain the rolemappings.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: The role.
|
||||
"""
|
||||
client_roles_url = URL_ROLES_BY_ID_COMPOSITES_CLIENTS.format(url=self.baseurl, realm=realm, id=rid, cid=cid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(client_roles_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch role for id %s and cid %s in realm %s: %s"
|
||||
% (rid, cid, realm, str(e)))
|
||||
|
||||
def add_client_roles_by_id_composite_rolemapping(self, rid, roles_rep, realm="master"):
|
||||
""" Assign roles to composite role
|
||||
|
||||
:param rid: ID of the composite role.
|
||||
:param roles_rep: Representation of the roles to assign.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: None.
|
||||
"""
|
||||
available_rolemappings_url = URL_ROLES_BY_ID_COMPOSITES.format(url=self.baseurl, realm=realm, id=rid)
|
||||
try:
|
||||
open_url(available_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(roles_rep),
|
||||
validate_certs=self.validate_certs, timeout=self.connection_timeout)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not assign roles to composite role %s and realm %s: %s"
|
||||
% (rid, realm, str(e)))
|
||||
|
||||
def add_group_rolemapping(self, gid, cid, role_rep, realm="master"):
|
||||
""" Fetch the composite role of a client in a specified goup on the Keycloak server.
|
||||
|
||||
|
@ -526,7 +587,7 @@ class KeycloakAPI(object):
|
|||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: None.
|
||||
"""
|
||||
available_rolemappings_url = URL_CLIENT_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
available_rolemappings_url = URL_CLIENT_GROUP_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
try:
|
||||
open_url(available_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
|
||||
validate_certs=self.validate_certs, timeout=self.connection_timeout)
|
||||
|
@ -543,7 +604,7 @@ class KeycloakAPI(object):
|
|||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: None.
|
||||
"""
|
||||
available_rolemappings_url = URL_CLIENT_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
available_rolemappings_url = URL_CLIENT_GROUP_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
|
||||
try:
|
||||
open_url(available_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders,
|
||||
validate_certs=self.validate_certs, timeout=self.connection_timeout)
|
||||
|
@ -551,6 +612,206 @@ class KeycloakAPI(object):
|
|||
self.module.fail_json(msg="Could not delete available rolemappings for client %s in group %s, realm %s: %s"
|
||||
% (cid, gid, realm, str(e)))
|
||||
|
||||
def get_client_user_rolemapping_by_id(self, uid, cid, rid, realm='master'):
|
||||
""" Obtain client representation by id
|
||||
|
||||
:param uid: ID of the user from which to obtain the rolemappings.
|
||||
:param cid: ID of the client from which to obtain the rolemappings.
|
||||
:param rid: ID of the role.
|
||||
:param realm: client from this realm
|
||||
:return: dict of rolemapping representation or None if none matching exist
|
||||
"""
|
||||
rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid, client=cid)
|
||||
try:
|
||||
rolemappings = json.loads(to_native(open_url(rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
for role in rolemappings:
|
||||
if rid == role['id']:
|
||||
return role
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch rolemappings for client %s and user %s, realm %s: %s"
|
||||
% (cid, uid, realm, str(e)))
|
||||
return None
|
||||
|
||||
def get_client_user_available_rolemappings(self, uid, cid, realm="master"):
|
||||
""" Fetch the available role of a client for a specified user on the Keycloak server.
|
||||
|
||||
:param uid: ID of the user from which to obtain the rolemappings.
|
||||
:param cid: ID of the client from which to obtain the rolemappings.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: The effective rollemappings of specified client and user of the realm (default "master").
|
||||
"""
|
||||
available_rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS_AVAILABLE.format(url=self.baseurl, realm=realm, id=uid, client=cid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(available_rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch effective rolemappings for client %s and user %s, realm %s: %s"
|
||||
% (cid, uid, realm, str(e)))
|
||||
|
||||
def get_client_user_composite_rolemappings(self, uid, cid, realm="master"):
|
||||
""" Fetch the composite role of a client for a specified user on the Keycloak server.
|
||||
|
||||
:param uid: ID of the user from which to obtain the rolemappings.
|
||||
:param cid: ID of the client from which to obtain the rolemappings.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: The rollemappings of specified group and client of the realm (default "master").
|
||||
"""
|
||||
composite_rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS_COMPOSITE.format(url=self.baseurl, realm=realm, id=uid, client=cid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(composite_rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch available rolemappings for user %s of realm %s: %s"
|
||||
% (uid, realm, str(e)))
|
||||
|
||||
def get_realm_user_rolemapping_by_id(self, uid, rid, realm='master'):
|
||||
""" Obtain role representation by id
|
||||
|
||||
:param uid: ID of the user from which to obtain the rolemappings.
|
||||
:param rid: ID of the role.
|
||||
:param realm: client from this realm
|
||||
:return: dict of rolemapping representation or None if none matching exist
|
||||
"""
|
||||
rolemappings_url = URL_REALM_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid)
|
||||
try:
|
||||
rolemappings = json.loads(to_native(open_url(rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
for role in rolemappings:
|
||||
if rid == role['id']:
|
||||
return role
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch rolemappings for user %s, realm %s: %s"
|
||||
% (uid, realm, str(e)))
|
||||
return None
|
||||
|
||||
def get_realm_user_available_rolemappings(self, uid, realm="master"):
|
||||
""" Fetch the available role of a realm for a specified user on the Keycloak server.
|
||||
|
||||
:param uid: ID of the user from which to obtain the rolemappings.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: The rollemappings of specified group and client of the realm (default "master").
|
||||
"""
|
||||
available_rolemappings_url = URL_REALM_ROLEMAPPINGS_AVAILABLE.format(url=self.baseurl, realm=realm, id=uid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(available_rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch available rolemappings for user %s of realm %s: %s"
|
||||
% (uid, realm, str(e)))
|
||||
|
||||
def get_realm_user_composite_rolemappings(self, uid, realm="master"):
|
||||
""" Fetch the composite role of a realm for a specified user on the Keycloak server.
|
||||
|
||||
:param uid: ID of the user from which to obtain the rolemappings.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: The effective rollemappings of specified client and user of the realm (default "master").
|
||||
"""
|
||||
composite_rolemappings_url = URL_REALM_ROLEMAPPINGS_COMPOSITE.format(url=self.baseurl, realm=realm, id=uid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(composite_rolemappings_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch effective rolemappings for user %s, realm %s: %s"
|
||||
% (uid, realm, str(e)))
|
||||
|
||||
def get_user_by_username(self, username, realm="master"):
|
||||
""" Fetch a keycloak user within a realm based on its username.
|
||||
|
||||
If the user does not exist, None is returned.
|
||||
:param username: Username of the user to fetch.
|
||||
:param realm: Realm in which the user resides; default 'master'
|
||||
"""
|
||||
users_url = URL_USERS.format(url=self.baseurl, realm=realm)
|
||||
users_url += '?username=%s&exact=true' % username
|
||||
try:
|
||||
return json.loads(to_native(open_url(users_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except ValueError as e:
|
||||
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain the user for realm %s and username %s: %s'
|
||||
% (realm, username, str(e)))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg='Could not obtain the user for realm %s and username %s: %s'
|
||||
% (realm, username, str(e)))
|
||||
|
||||
def get_service_account_user_by_client_id(self, client_id, realm="master"):
|
||||
""" Fetch a keycloak service account user within a realm based on its client_id.
|
||||
|
||||
If the user does not exist, None is returned.
|
||||
:param client_id: clientId of the service account user to fetch.
|
||||
:param realm: Realm in which the user resides; default 'master'
|
||||
"""
|
||||
cid = self.get_client_id(client_id, realm=realm)
|
||||
|
||||
service_account_user_url = URL_CLIENT_SERVICE_ACCOUNT_USER.format(url=self.baseurl, realm=realm, id=cid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(service_account_user_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except ValueError as e:
|
||||
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain the service-account-user for realm %s and client_id %s: %s'
|
||||
% (realm, client_id, str(e)))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg='Could not obtain the service-account-user for realm %s and client_id %s: %s'
|
||||
% (realm, client_id, str(e)))
|
||||
|
||||
def add_user_rolemapping(self, uid, cid, role_rep, realm="master"):
|
||||
""" Assign a realm or client role to a specified user on the Keycloak server.
|
||||
|
||||
:param uid: ID of the user roles are assigned to.
|
||||
:param cid: ID of the client from which to obtain the rolemappings. If empty, roles are from the realm
|
||||
:param role_rep: Representation of the role to assign.
|
||||
:param realm: Realm from which to obtain the rolemappings.
|
||||
:return: None.
|
||||
"""
|
||||
if cid is None:
|
||||
user_realm_rolemappings_url = URL_REALM_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid)
|
||||
try:
|
||||
open_url(user_realm_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
|
||||
validate_certs=self.validate_certs, timeout=self.connection_timeout)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not map roles to userId %s for realm %s and roles %s: %s"
|
||||
% (uid, realm, json.dumps(role_rep), str(e)))
|
||||
else:
|
||||
user_client_rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid, client=cid)
|
||||
try:
|
||||
open_url(user_client_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
|
||||
validate_certs=self.validate_certs, timeout=self.connection_timeout)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not map roles to userId %s for client %s, realm %s and roles %s: %s"
|
||||
% (cid, uid, realm, json.dumps(role_rep), str(e)))
|
||||
|
||||
def delete_user_rolemapping(self, uid, cid, role_rep, realm="master"):
|
||||
""" Delete the rolemapping of a client in a specified user on the Keycloak server.
|
||||
|
||||
:param uid: ID of the user from which to remove the rolemappings.
|
||||
:param cid: ID of the client from which to remove the rolemappings.
|
||||
:param role_rep: Representation of the role to remove from rolemappings.
|
||||
:param realm: Realm from which to remove the rolemappings.
|
||||
:return: None.
|
||||
"""
|
||||
if cid is None:
|
||||
user_realm_rolemappings_url = URL_REALM_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid)
|
||||
try:
|
||||
open_url(user_realm_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
|
||||
validate_certs=self.validate_certs, timeout=self.connection_timeout)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not remove roles %s from userId %s, realm %s: %s"
|
||||
% (json.dumps(role_rep), uid, realm, str(e)))
|
||||
else:
|
||||
user_client_rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid, client=cid)
|
||||
try:
|
||||
open_url(user_client_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
|
||||
validate_certs=self.validate_certs, timeout=self.connection_timeout)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not remove roles %s for client %s from userId %s, realm %s: %s"
|
||||
% (json.dumps(role_rep), cid, uid, realm, str(e)))
|
||||
|
||||
def get_client_templates(self, realm='master'):
|
||||
""" Obtains client template representations for client templates in a realm
|
||||
|
||||
|
@ -930,7 +1191,6 @@ class KeycloakAPI(object):
|
|||
return json.loads(to_native(open_url(groups_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
return None
|
||||
|
|
|
@ -279,20 +279,20 @@ def main():
|
|||
module.fail_json(msg='Either the `name` or `id` has to be specified on each role.')
|
||||
# Fetch missing role_id
|
||||
if role['id'] is None:
|
||||
role_id = kc.get_client_role_by_name(gid, cid, role['name'], realm=realm)
|
||||
role_id = kc.get_client_role_id_by_name(cid, role['name'], realm=realm)
|
||||
if role_id is not None:
|
||||
role['id'] = role_id
|
||||
else:
|
||||
module.fail_json(msg='Could not fetch role %s:' % (role['name']))
|
||||
# Fetch missing role_name
|
||||
else:
|
||||
role['name'] = kc.get_client_rolemapping_by_id(gid, cid, role['id'], realm=realm)['name']
|
||||
role['name'] = kc.get_client_group_rolemapping_by_id(gid, cid, role['id'], realm=realm)['name']
|
||||
if role['name'] is None:
|
||||
module.fail_json(msg='Could not fetch role %s' % (role['id']))
|
||||
|
||||
# Get effective client-level role mappings
|
||||
available_roles_before = kc.get_client_available_rolemappings(gid, cid, realm=realm)
|
||||
assigned_roles_before = kc.get_client_composite_rolemappings(gid, cid, realm=realm)
|
||||
available_roles_before = kc.get_client_group_available_rolemappings(gid, cid, realm=realm)
|
||||
assigned_roles_before = kc.get_client_group_composite_rolemappings(gid, cid, realm=realm)
|
||||
|
||||
result['existing'] = assigned_roles_before
|
||||
result['proposed'] = roles
|
||||
|
@ -326,7 +326,7 @@ def main():
|
|||
module.exit_json(**result)
|
||||
kc.add_group_rolemapping(gid, cid, update_roles, realm=realm)
|
||||
result['msg'] = 'Roles %s assigned to group %s.' % (update_roles, group_name)
|
||||
assigned_roles_after = kc.get_client_composite_rolemappings(gid, cid, realm=realm)
|
||||
assigned_roles_after = kc.get_client_group_composite_rolemappings(gid, cid, realm=realm)
|
||||
result['end_state'] = assigned_roles_after
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
|
@ -338,7 +338,7 @@ def main():
|
|||
module.exit_json(**result)
|
||||
kc.delete_group_rolemapping(gid, cid, update_roles, realm=realm)
|
||||
result['msg'] = 'Roles %s removed from group %s.' % (update_roles, group_name)
|
||||
assigned_roles_after = kc.get_client_composite_rolemappings(gid, cid, realm=realm)
|
||||
assigned_roles_after = kc.get_client_group_composite_rolemappings(gid, cid, realm=realm)
|
||||
result['end_state'] = assigned_roles_after
|
||||
module.exit_json(**result)
|
||||
# Do nothing
|
||||
|
|
401
plugins/modules/identity/keycloak/keycloak_user_rolemapping.py
Normal file
401
plugins/modules/identity/keycloak/keycloak_user_rolemapping.py
Normal file
|
@ -0,0 +1,401 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2022, Dušan Marković (@bratwurzt)
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: keycloak_user_rolemapping
|
||||
|
||||
short_description: Allows administration of Keycloak user_rolemapping with the Keycloak API
|
||||
|
||||
version_added: 5.7.0
|
||||
|
||||
description:
|
||||
- This module allows you to add, remove or modify Keycloak user_rolemapping with the Keycloak REST API.
|
||||
It requires access to the REST API via OpenID Connect; the user connecting and the client being
|
||||
used must have the requisite access rights. In a default Keycloak installation, admin-cli
|
||||
and an admin user would work, as would a separate client definition with the scope tailored
|
||||
to your needs and a user having the expected roles.
|
||||
|
||||
- The names of module options are snake_cased versions of the camelCase ones found in the
|
||||
Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/8.0/rest-api/index.html).
|
||||
|
||||
- Attributes are multi-valued in the Keycloak API. All attributes are lists of individual values and will
|
||||
be returned that way by this module. You may pass single values for attributes when calling the module,
|
||||
and this will be translated into a list suitable for the API.
|
||||
|
||||
- When updating a user_rolemapping, where possible provide the role ID to the module. This removes a lookup
|
||||
to the API to translate the name into the role ID.
|
||||
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- State of the user_rolemapping.
|
||||
- On C(present), the user_rolemapping will be created if it does not yet exist, or updated with the parameters you provide.
|
||||
- On C(absent), the user_rolemapping will be removed if it exists.
|
||||
default: 'present'
|
||||
type: str
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
|
||||
realm:
|
||||
type: str
|
||||
description:
|
||||
- They Keycloak realm under which this role_representation resides.
|
||||
default: 'master'
|
||||
|
||||
target_username:
|
||||
type: str
|
||||
description:
|
||||
- Username of the user roles are mapped to.
|
||||
- This parameter is not required (can be replaced by uid for less API call).
|
||||
|
||||
uid:
|
||||
type: str
|
||||
description:
|
||||
- ID of the user to be mapped.
|
||||
- This parameter is not required for updating or deleting the rolemapping but
|
||||
providing it will reduce the number of API calls required.
|
||||
|
||||
service_account_user_client_id:
|
||||
type: str
|
||||
description:
|
||||
- Client ID of the service-account-user to be mapped.
|
||||
- This parameter is not required for updating or deleting the rolemapping but
|
||||
providing it will reduce the number of API calls required.
|
||||
|
||||
client_id:
|
||||
type: str
|
||||
description:
|
||||
- Name of the client to be mapped (different than I(cid)).
|
||||
- This parameter is required if I(cid) is not provided (can be replaced by I(cid)
|
||||
to reduce the number of API calls that must be made).
|
||||
|
||||
cid:
|
||||
type: str
|
||||
description:
|
||||
- ID of the client to be mapped.
|
||||
- This parameter is not required for updating or deleting the rolemapping but
|
||||
providing it will reduce the number of API calls required.
|
||||
|
||||
roles:
|
||||
description:
|
||||
- Roles to be mapped to the user.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
type: str
|
||||
description:
|
||||
- Name of the role representation.
|
||||
- This parameter is required only when creating or updating the role_representation.
|
||||
id:
|
||||
type: str
|
||||
description:
|
||||
- The unique identifier for this role_representation.
|
||||
- This parameter is not required for updating or deleting a role_representation but
|
||||
providing it will reduce the number of API calls required.
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.general.keycloak
|
||||
|
||||
|
||||
author:
|
||||
- Dušan Marković (@bratwurzt)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Map a client role to a user, authentication with credentials
|
||||
community.general.keycloak_user_rolemapping:
|
||||
realm: MyCustomRealm
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: USERNAME
|
||||
auth_password: PASSWORD
|
||||
state: present
|
||||
client_id: client1
|
||||
user_id: user1Id
|
||||
roles:
|
||||
- name: role_name1
|
||||
id: role_id1
|
||||
- name: role_name2
|
||||
id: role_id2
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Map a client role to a service account user for a client, authentication with credentials
|
||||
community.general.keycloak_user_rolemapping:
|
||||
realm: MyCustomRealm
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: USERNAME
|
||||
auth_password: PASSWORD
|
||||
state: present
|
||||
client_id: client1
|
||||
service_account_user_client_id: clientIdOfServiceAccount
|
||||
roles:
|
||||
- name: role_name1
|
||||
id: role_id1
|
||||
- name: role_name2
|
||||
id: role_id2
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Map a client role to a user, authentication with token
|
||||
community.general.keycloak_user_rolemapping:
|
||||
realm: MyCustomRealm
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
token: TOKEN
|
||||
state: present
|
||||
client_id: client1
|
||||
target_username: user1
|
||||
roles:
|
||||
- name: role_name1
|
||||
id: role_id1
|
||||
- name: role_name2
|
||||
id: role_id2
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Unmap client role from a user
|
||||
community.general.keycloak_user_rolemapping:
|
||||
realm: MyCustomRealm
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: USERNAME
|
||||
auth_password: PASSWORD
|
||||
state: absent
|
||||
client_id: client1
|
||||
uid: 70e3ae72-96b6-11e6-9056-9737fd4d0764
|
||||
roles:
|
||||
- name: role_name1
|
||||
id: role_id1
|
||||
- name: role_name2
|
||||
id: role_id2
|
||||
delegate_to: localhost
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Role role1 assigned to user user1."
|
||||
|
||||
proposed:
|
||||
description: Representation of proposed client role mapping.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
clientId: "test"
|
||||
}
|
||||
|
||||
existing:
|
||||
description:
|
||||
- Representation of existing client role mapping.
|
||||
- The sample is truncated.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
"attributes": {
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
|
||||
end_state:
|
||||
description:
|
||||
- Representation of client role mapping after module execution.
|
||||
- The sample is truncated.
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
"attributes": {
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
|
||||
keycloak_argument_spec, get_token, KeycloakError, is_struct_included
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Module execution
|
||||
|
||||
:return:
|
||||
"""
|
||||
argument_spec = keycloak_argument_spec()
|
||||
|
||||
roles_spec = dict(
|
||||
name=dict(type='str'),
|
||||
id=dict(type='str'),
|
||||
)
|
||||
|
||||
meta_args = dict(
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
realm=dict(default='master'),
|
||||
uid=dict(type='str'),
|
||||
target_username=dict(type='str'),
|
||||
service_account_user_client_id=dict(type='str'),
|
||||
cid=dict(type='str'),
|
||||
client_id=dict(type='str'),
|
||||
roles=dict(type='list', elements='dict', options=roles_spec),
|
||||
)
|
||||
|
||||
argument_spec.update(meta_args)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password'],
|
||||
['uid', 'target_username', 'service_account_user_client_id']]),
|
||||
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
|
||||
|
||||
result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})
|
||||
|
||||
# Obtain access token, initialize API
|
||||
try:
|
||||
connection_header = get_token(module.params)
|
||||
except KeycloakError as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
kc = KeycloakAPI(module, connection_header)
|
||||
|
||||
realm = module.params.get('realm')
|
||||
state = module.params.get('state')
|
||||
cid = module.params.get('cid')
|
||||
client_id = module.params.get('client_id')
|
||||
uid = module.params.get('uid')
|
||||
target_username = module.params.get('target_username')
|
||||
service_account_user_client_id = module.params.get('service_account_user_client_id')
|
||||
roles = module.params.get('roles')
|
||||
|
||||
# Check the parameters
|
||||
if uid is None and target_username is None and service_account_user_client_id is None:
|
||||
module.fail_json(msg='Either the `target_username`, `uid` or `service_account_user_client_id` has to be specified.')
|
||||
|
||||
# Get the potential missing parameters
|
||||
if uid is None and service_account_user_client_id is None:
|
||||
user_rep = kc.get_user_by_username(username=target_username, realm=realm)
|
||||
if user_rep is not None:
|
||||
uid = user_rep.get('id')
|
||||
else:
|
||||
module.fail_json(msg='Could not fetch user for username %s:' % target_username)
|
||||
else:
|
||||
if uid is None and target_username is None:
|
||||
user_rep = kc.get_service_account_user_by_client_id(client_id=service_account_user_client_id, realm=realm)
|
||||
if user_rep is not None:
|
||||
uid = user_rep['id']
|
||||
else:
|
||||
module.fail_json(msg='Could not fetch service-account-user for client_id %s:' % target_username)
|
||||
|
||||
if cid is None and client_id is not None:
|
||||
cid = kc.get_client_id(client_id=client_id, realm=realm)
|
||||
if cid is None:
|
||||
module.fail_json(msg='Could not fetch client %s:' % client_id)
|
||||
if roles is None:
|
||||
module.exit_json(msg="Nothing to do (no roles specified).")
|
||||
else:
|
||||
for role_index, role in enumerate(roles, start=0):
|
||||
if role.get('name') is None and role.get('id') is None:
|
||||
module.fail_json(msg='Either the `name` or `id` has to be specified on each role.')
|
||||
# Fetch missing role_id
|
||||
if role.get('id') is None:
|
||||
if cid is None:
|
||||
role_id = kc.get_realm_role(name=role.get('name'), realm=realm)['id']
|
||||
else:
|
||||
role_id = kc.get_client_role_id_by_name(cid=cid, name=role.get('name'), realm=realm)
|
||||
if role_id is not None:
|
||||
role['id'] = role_id
|
||||
else:
|
||||
module.fail_json(msg='Could not fetch role %s for client_id %s or realm %s' % (role.get('name'), client_id, realm))
|
||||
# Fetch missing role_name
|
||||
else:
|
||||
if cid is None:
|
||||
role['name'] = kc.get_realm_user_rolemapping_by_id(uid=uid, rid=role.get('id'), realm=realm)['name']
|
||||
else:
|
||||
role['name'] = kc.get_client_user_rolemapping_by_id(uid=uid, cid=cid, rid=role.get('id'), realm=realm)['name']
|
||||
if role.get('name') is None:
|
||||
module.fail_json(msg='Could not fetch role %s for client_id %s or realm %s' % (role.get('id'), client_id, realm))
|
||||
|
||||
# Get effective role mappings
|
||||
if cid is None:
|
||||
available_roles_before = kc.get_realm_user_available_rolemappings(uid=uid, realm=realm)
|
||||
assigned_roles_before = kc.get_realm_user_composite_rolemappings(uid=uid, realm=realm)
|
||||
else:
|
||||
available_roles_before = kc.get_client_user_available_rolemappings(uid=uid, cid=cid, realm=realm)
|
||||
assigned_roles_before = kc.get_client_user_composite_rolemappings(uid=uid, cid=cid, realm=realm)
|
||||
|
||||
result['existing'] = assigned_roles_before
|
||||
result['proposed'] = roles
|
||||
|
||||
update_roles = []
|
||||
for role_index, role in enumerate(roles, start=0):
|
||||
# Fetch roles to assign if state present
|
||||
if state == 'present':
|
||||
for available_role in available_roles_before:
|
||||
if role.get('name') == available_role.get('name'):
|
||||
update_roles.append({
|
||||
'id': role.get('id'),
|
||||
'name': role.get('name'),
|
||||
})
|
||||
# Fetch roles to remove if state absent
|
||||
else:
|
||||
for assigned_role in assigned_roles_before:
|
||||
if role.get('name') == assigned_role.get('name'):
|
||||
update_roles.append({
|
||||
'id': role.get('id'),
|
||||
'name': role.get('name'),
|
||||
})
|
||||
|
||||
if len(update_roles):
|
||||
if state == 'present':
|
||||
# Assign roles
|
||||
result['changed'] = True
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=assigned_roles_before, after=update_roles)
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
kc.add_user_rolemapping(uid=uid, cid=cid, role_rep=update_roles, realm=realm)
|
||||
result['msg'] = 'Roles %s assigned to userId %s.' % (update_roles, uid)
|
||||
if cid is None:
|
||||
assigned_roles_after = kc.get_realm_user_composite_rolemappings(uid=uid, realm=realm)
|
||||
else:
|
||||
assigned_roles_after = kc.get_client_user_composite_rolemappings(uid=uid, cid=cid, realm=realm)
|
||||
result['end_state'] = assigned_roles_after
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
# Remove mapping of role
|
||||
result['changed'] = True
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=assigned_roles_before, after=update_roles)
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
kc.delete_user_rolemapping(uid=uid, cid=cid, role_rep=update_roles, realm=realm)
|
||||
result['msg'] = 'Roles %s removed from userId %s.' % (update_roles, uid)
|
||||
if cid is None:
|
||||
assigned_roles_after = kc.get_realm_user_composite_rolemappings(uid=uid, realm=realm)
|
||||
else:
|
||||
assigned_roles_after = kc.get_client_user_composite_rolemappings(uid=uid, cid=cid, realm=realm)
|
||||
result['end_state'] = assigned_roles_after
|
||||
module.exit_json(**result)
|
||||
# Do nothing
|
||||
else:
|
||||
result['changed'] = False
|
||||
result['msg'] = 'Nothing to do, roles %s are correctly mapped to user for username %s.' % (roles, target_username)
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) 2022, Dušan Marković (@bratwurzt)
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
unsupported
|
|
@ -0,0 +1,143 @@
|
|||
# Copyright (c) 2022, Dušan Marković (@bratwurzt)
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
- name: Create realm
|
||||
community.general.keycloak_realm:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
id: "{{ realm }}"
|
||||
realm: "{{ realm }}"
|
||||
state: present
|
||||
|
||||
- name: Create client
|
||||
community.general.keycloak_client:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
service_accounts_enabled: True
|
||||
state: present
|
||||
register: client
|
||||
|
||||
- name: Create new realm role
|
||||
community.general.keycloak_role:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
name: "{{ role }}"
|
||||
description: "{{ description_1 }}"
|
||||
state: present
|
||||
|
||||
- name: Map a realm role to client service account
|
||||
vars:
|
||||
- roles: [ {'name': '{{ role }}'} ]
|
||||
community.general.keycloak_user_rolemapping:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
service_account_user_client_id: "{{ client_id }}"
|
||||
roles: "{{ roles }}"
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert realm role is assigned
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state | selectattr("clientRole", "eq", false) | selectattr("name", "eq", "{{role}}") | list | count > 0
|
||||
|
||||
- name: Unmap a realm role from client service account
|
||||
vars:
|
||||
- roles: [ {'name': '{{ role }}'} ]
|
||||
community.general.keycloak_user_rolemapping:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
service_account_user_client_id: "{{ client_id }}"
|
||||
roles: "{{ roles }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Assert realm role is unassigned
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- (result.end_state | length) == (result.existing | length) - 1
|
||||
- result.existing | selectattr("clientRole", "eq", false) | selectattr("name", "eq", "{{role}}") | list | count > 0
|
||||
- result.end_state | selectattr("clientRole", "eq", false) | selectattr("name", "eq", "{{role}}") | list | count == 0
|
||||
|
||||
- name: Delete existing realm role
|
||||
community.general.keycloak_role:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
name: "{{ role }}"
|
||||
state: absent
|
||||
|
||||
- name: Create new client role
|
||||
community.general.keycloak_role:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
name: "{{ role }}"
|
||||
description: "{{ description_1 }}"
|
||||
state: present
|
||||
|
||||
- name: Map a client role to client service account
|
||||
vars:
|
||||
- roles: [ {'name': '{{ role }}'} ]
|
||||
community.general.keycloak_user_rolemapping:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
service_account_user_client_id: "{{ client_id }}"
|
||||
roles: "{{ roles }}"
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert client role is assigned
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state | selectattr("clientRole", "eq", true) | selectattr("name", "eq", "{{role}}") | list | count > 0
|
||||
|
||||
- name: Unmap a client role from client service account
|
||||
vars:
|
||||
- roles: [ {'name': '{{ role }}'} ]
|
||||
community.general.keycloak_user_rolemapping:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
service_account_user_client_id: "{{ client_id }}"
|
||||
roles: "{{ roles }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Assert client role is unassigned
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state == []
|
||||
- result.existing | selectattr("clientRole", "eq", true) | selectattr("name", "eq", "{{role}}") | list | count > 0
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
# Copyright (c) 2022, Dušan Marković (@bratwurzt)
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
url: http://localhost:8080/auth
|
||||
admin_realm: master
|
||||
admin_user: admin
|
||||
admin_password: password
|
||||
realm: myrealm
|
||||
client_id: myclient
|
||||
role: myrole
|
||||
description_1: desc 1
|
||||
description_2: desc 2
|
|
@ -21,9 +21,9 @@ from ansible.module_utils.six import StringIO
|
|||
|
||||
|
||||
@contextmanager
|
||||
def patch_keycloak_api(get_group_by_name=None, get_client_id=None, get_client_role_by_name=None,
|
||||
get_client_rolemapping_by_id=None, get_client_available_rolemappings=None,
|
||||
get_client_composite_rolemappings=None, add_group_rolemapping=None,
|
||||
def patch_keycloak_api(get_group_by_name=None, get_client_id=None, get_client_role_id_by_name=None,
|
||||
get_client_group_rolemapping_by_id=None, get_client_group_available_rolemappings=None,
|
||||
get_client_group_composite_rolemappings=None, add_group_rolemapping=None,
|
||||
delete_group_rolemapping=None):
|
||||
"""Mock context manager for patching the methods in PwPolicyIPAClient that contact the IPA server
|
||||
|
||||
|
@ -44,21 +44,21 @@ def patch_keycloak_api(get_group_by_name=None, get_client_id=None, get_client_ro
|
|||
side_effect=get_group_by_name) as mock_get_group_by_name:
|
||||
with patch.object(obj, 'get_client_id',
|
||||
side_effect=get_client_id) as mock_get_client_id:
|
||||
with patch.object(obj, 'get_client_role_by_name',
|
||||
side_effect=get_client_role_by_name) as mock_get_client_role_by_name:
|
||||
with patch.object(obj, 'get_client_rolemapping_by_id',
|
||||
side_effect=get_client_rolemapping_by_id) as mock_get_client_rolemapping_by_id:
|
||||
with patch.object(obj, 'get_client_available_rolemappings',
|
||||
side_effect=get_client_available_rolemappings) as mock_get_client_available_rolemappings:
|
||||
with patch.object(obj, 'get_client_composite_rolemappings',
|
||||
side_effect=get_client_composite_rolemappings) as mock_get_client_composite_rolemappings:
|
||||
with patch.object(obj, 'get_client_role_id_by_name',
|
||||
side_effect=get_client_role_id_by_name) as mock_get_client_role_id_by_name:
|
||||
with patch.object(obj, 'get_client_group_rolemapping_by_id',
|
||||
side_effect=get_client_group_rolemapping_by_id) as mock_get_client_group_rolemapping_by_id:
|
||||
with patch.object(obj, 'get_client_group_available_rolemappings',
|
||||
side_effect=get_client_group_available_rolemappings) as mock_get_client_group_available_rolemappings:
|
||||
with patch.object(obj, 'get_client_group_composite_rolemappings',
|
||||
side_effect=get_client_group_composite_rolemappings) as mock_get_client_group_composite_rolemappings:
|
||||
with patch.object(obj, 'add_group_rolemapping',
|
||||
side_effect=add_group_rolemapping) as mock_add_group_rolemapping:
|
||||
with patch.object(obj, 'delete_group_rolemapping',
|
||||
side_effect=delete_group_rolemapping) as mock_delete_group_rolemapping:
|
||||
yield mock_get_group_by_name, mock_get_client_id, mock_get_client_role_by_name, mock_add_group_rolemapping, \
|
||||
mock_get_client_rolemapping_by_id, mock_get_client_available_rolemappings, mock_get_client_composite_rolemappings, \
|
||||
mock_delete_group_rolemapping
|
||||
yield mock_get_group_by_name, mock_get_client_id, mock_get_client_role_id_by_name, mock_add_group_rolemapping, \
|
||||
mock_get_client_group_rolemapping_by_id, mock_get_client_group_available_rolemappings, \
|
||||
mock_get_client_group_composite_rolemappings, mock_delete_group_rolemapping
|
||||
|
||||
|
||||
def get_response(object_with_future_response, method, get_id_call_count):
|
||||
|
@ -144,8 +144,8 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
"subGroups": "[]"
|
||||
}]
|
||||
return_value_get_client_id = "c0f8490c-b224-4737-a567-20223e4c1727"
|
||||
return_value_get_client_role_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_available_rolemappings = [[
|
||||
return_value_get_client_role_id_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_group_available_rolemappings = [[
|
||||
{
|
||||
"clientRole": "true",
|
||||
"composite": "false",
|
||||
|
@ -161,7 +161,7 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
"name": "test_role1"
|
||||
}
|
||||
]]
|
||||
return_value_get_client_composite_rolemappings = [
|
||||
return_value_get_client_group_composite_rolemappings = [
|
||||
None,
|
||||
[
|
||||
{
|
||||
|
@ -189,11 +189,11 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_group_by_name=return_value_get_group_by_name, get_client_id=return_value_get_client_id,
|
||||
get_client_role_by_name=return_value_get_client_role_by_name,
|
||||
get_client_available_rolemappings=return_value_get_client_available_rolemappings,
|
||||
get_client_composite_rolemappings=return_value_get_client_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_rolemapping_by_id, mock_get_client_available_rolemappings, mock_get_client_composite_rolemappings,
|
||||
get_client_role_id_by_name=return_value_get_client_role_id_by_name,
|
||||
get_client_group_available_rolemappings=return_value_get_client_group_available_rolemappings,
|
||||
get_client_group_composite_rolemappings=return_value_get_client_group_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_id_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_group_rolemapping_by_id, mock_get_client_group_available_rolemappings, mock_get_client_group_composite_rolemappings,
|
||||
mock_delete_group_rolemapping):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
@ -201,9 +201,9 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
self.assertEqual(mock_get_group_by_name.call_count, 1)
|
||||
self.assertEqual(mock_get_client_id.call_count, 1)
|
||||
self.assertEqual(mock_add_group_rolemapping.call_count, 1)
|
||||
self.assertEqual(mock_get_client_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_composite_rolemappings.call_count, 2)
|
||||
self.assertEqual(mock_get_client_group_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_group_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_group_composite_rolemappings.call_count, 2)
|
||||
self.assertEqual(mock_delete_group_rolemapping.call_count, 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
|
@ -246,9 +246,9 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
"subGroups": "[]"
|
||||
}]
|
||||
return_value_get_client_id = "c0f8490c-b224-4737-a567-20223e4c1727"
|
||||
return_value_get_client_role_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_available_rolemappings = [[]]
|
||||
return_value_get_client_composite_rolemappings = [[
|
||||
return_value_get_client_role_id_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_group_available_rolemappings = [[]]
|
||||
return_value_get_client_group_composite_rolemappings = [[
|
||||
{
|
||||
"clientRole": "true",
|
||||
"composite": "false",
|
||||
|
@ -273,11 +273,11 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_group_by_name=return_value_get_group_by_name, get_client_id=return_value_get_client_id,
|
||||
get_client_role_by_name=return_value_get_client_role_by_name,
|
||||
get_client_available_rolemappings=return_value_get_client_available_rolemappings,
|
||||
get_client_composite_rolemappings=return_value_get_client_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_rolemapping_by_id, mock_get_client_available_rolemappings, mock_get_client_composite_rolemappings,
|
||||
get_client_role_id_by_name=return_value_get_client_role_id_by_name,
|
||||
get_client_group_available_rolemappings=return_value_get_client_group_available_rolemappings,
|
||||
get_client_group_composite_rolemappings=return_value_get_client_group_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_id_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_group_rolemapping_by_id, mock_get_client_group_available_rolemappings, mock_get_client_group_composite_rolemappings,
|
||||
mock_delete_group_rolemapping):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
@ -285,9 +285,9 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
self.assertEqual(mock_get_group_by_name.call_count, 1)
|
||||
self.assertEqual(mock_get_client_id.call_count, 1)
|
||||
self.assertEqual(mock_add_group_rolemapping.call_count, 0)
|
||||
self.assertEqual(mock_get_client_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_composite_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_group_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_group_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_group_composite_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_delete_group_rolemapping.call_count, 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
|
@ -330,8 +330,8 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
"subGroups": "[]"
|
||||
}]
|
||||
return_value_get_client_id = "c0f8490c-b224-4737-a567-20223e4c1727"
|
||||
return_value_get_client_role_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_available_rolemappings = [[
|
||||
return_value_get_client_role_id_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_group_available_rolemappings = [[
|
||||
{
|
||||
"clientRole": "true",
|
||||
"composite": "false",
|
||||
|
@ -347,7 +347,7 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
"name": "test_role1"
|
||||
}
|
||||
]]
|
||||
return_value_get_client_composite_rolemappings = [
|
||||
return_value_get_client_group_composite_rolemappings = [
|
||||
None,
|
||||
[
|
||||
{
|
||||
|
@ -375,11 +375,11 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_group_by_name=return_value_get_group_by_name, get_client_id=return_value_get_client_id,
|
||||
get_client_role_by_name=return_value_get_client_role_by_name,
|
||||
get_client_available_rolemappings=return_value_get_client_available_rolemappings,
|
||||
get_client_composite_rolemappings=return_value_get_client_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_rolemapping_by_id, mock_get_client_available_rolemappings, mock_get_client_composite_rolemappings,
|
||||
get_client_role_id_by_name=return_value_get_client_role_id_by_name,
|
||||
get_client_group_available_rolemappings=return_value_get_client_group_available_rolemappings,
|
||||
get_client_group_composite_rolemappings=return_value_get_client_group_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_id_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_group_rolemapping_by_id, mock_get_client_group_available_rolemappings, mock_get_client_group_composite_rolemappings,
|
||||
mock_delete_group_rolemapping):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
@ -387,9 +387,9 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
self.assertEqual(mock_get_group_by_name.call_count, 0)
|
||||
self.assertEqual(mock_get_client_id.call_count, 0)
|
||||
self.assertEqual(mock_add_group_rolemapping.call_count, 1)
|
||||
self.assertEqual(mock_get_client_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_composite_rolemappings.call_count, 2)
|
||||
self.assertEqual(mock_get_client_group_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_group_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_group_composite_rolemappings.call_count, 2)
|
||||
self.assertEqual(mock_delete_group_rolemapping.call_count, 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
|
@ -432,9 +432,9 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
"subGroups": "[]"
|
||||
}]
|
||||
return_value_get_client_id = "c0f8490c-b224-4737-a567-20223e4c1727"
|
||||
return_value_get_client_role_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_available_rolemappings = [[]]
|
||||
return_value_get_client_composite_rolemappings = [
|
||||
return_value_get_client_role_id_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_group_available_rolemappings = [[]]
|
||||
return_value_get_client_group_composite_rolemappings = [
|
||||
[
|
||||
{
|
||||
"clientRole": "true",
|
||||
|
@ -462,11 +462,11 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_group_by_name=return_value_get_group_by_name, get_client_id=return_value_get_client_id,
|
||||
get_client_role_by_name=return_value_get_client_role_by_name,
|
||||
get_client_available_rolemappings=return_value_get_client_available_rolemappings,
|
||||
get_client_composite_rolemappings=return_value_get_client_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_rolemapping_by_id, mock_get_client_available_rolemappings, mock_get_client_composite_rolemappings,
|
||||
get_client_role_id_by_name=return_value_get_client_role_id_by_name,
|
||||
get_client_group_available_rolemappings=return_value_get_client_group_available_rolemappings,
|
||||
get_client_group_composite_rolemappings=return_value_get_client_group_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_id_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_group_rolemapping_by_id, mock_get_client_group_available_rolemappings, mock_get_client_group_composite_rolemappings,
|
||||
mock_delete_group_rolemapping):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
@ -474,9 +474,9 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
self.assertEqual(mock_get_group_by_name.call_count, 1)
|
||||
self.assertEqual(mock_get_client_id.call_count, 1)
|
||||
self.assertEqual(mock_add_group_rolemapping.call_count, 0)
|
||||
self.assertEqual(mock_get_client_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_composite_rolemappings.call_count, 2)
|
||||
self.assertEqual(mock_get_client_group_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_group_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_group_composite_rolemappings.call_count, 2)
|
||||
self.assertEqual(mock_delete_group_rolemapping.call_count, 1)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
|
@ -519,8 +519,8 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
"subGroups": "[]"
|
||||
}]
|
||||
return_value_get_client_id = "c0f8490c-b224-4737-a567-20223e4c1727"
|
||||
return_value_get_client_role_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_available_rolemappings = [
|
||||
return_value_get_client_role_id_by_name = "e91af074-cfd5-40ee-8ef5-ae0ae1ce69fe"
|
||||
return_value_get_client_group_available_rolemappings = [
|
||||
[
|
||||
{
|
||||
"clientRole": "true",
|
||||
|
@ -538,7 +538,7 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
}
|
||||
]
|
||||
]
|
||||
return_value_get_client_composite_rolemappings = [[]]
|
||||
return_value_get_client_group_composite_rolemappings = [[]]
|
||||
|
||||
changed = False
|
||||
|
||||
|
@ -548,11 +548,11 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_group_by_name=return_value_get_group_by_name, get_client_id=return_value_get_client_id,
|
||||
get_client_role_by_name=return_value_get_client_role_by_name,
|
||||
get_client_available_rolemappings=return_value_get_client_available_rolemappings,
|
||||
get_client_composite_rolemappings=return_value_get_client_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_rolemapping_by_id, mock_get_client_available_rolemappings, mock_get_client_composite_rolemappings,
|
||||
get_client_role_id_by_name=return_value_get_client_role_id_by_name,
|
||||
get_client_group_available_rolemappings=return_value_get_client_group_available_rolemappings,
|
||||
get_client_group_composite_rolemappings=return_value_get_client_group_composite_rolemappings) \
|
||||
as (mock_get_group_by_name, mock_get_client_id, mock_get_client_role_id_by_name, mock_add_group_rolemapping,
|
||||
mock_get_client_group_rolemapping_by_id, mock_get_client_group_available_rolemappings, mock_get_client_group_composite_rolemappings,
|
||||
mock_delete_group_rolemapping):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
@ -560,9 +560,9 @@ class TestKeycloakRealm(ModuleTestCase):
|
|||
self.assertEqual(mock_get_group_by_name.call_count, 1)
|
||||
self.assertEqual(mock_get_client_id.call_count, 1)
|
||||
self.assertEqual(mock_add_group_rolemapping.call_count, 0)
|
||||
self.assertEqual(mock_get_client_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_composite_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_group_rolemapping_by_id.call_count, 0)
|
||||
self.assertEqual(mock_get_client_group_available_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_get_client_group_composite_rolemappings.call_count, 1)
|
||||
self.assertEqual(mock_delete_group_rolemapping.call_count, 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
|
|
Loading…
Reference in a new issue