def main(): argument_spec = keycloak_argument_spec() client_role_spec = dict( clientId=dict(type='str', required=True), roles=dict(type='list', required=True), ) meta_args = dict( realm=dict(type='str', default='master'), self=dict(type='str'), id=dict(type='str'), username=dict(type='str', required=True), firstName=dict(type='str'), lastName=dict(type='str'), email=dict(type='str'), enabled=dict(type='bool', default=True), emailVerified=dict(type='bool', default=False), federationLink=dict(type='str'), serviceAccountClientId=dict(type='str'), attributes=dict(type='dict'), access=dict(type='dict'), clientRoles=dict(type='list', default=[], options=client_role_spec), realmRoles=dict(type='list', default=[]), groups=dict(type='list', default=[]), disableableCredentialTypes=dict(type='list', default=[]), requiredActions=dict(type='list', default=[]), credentials=dict(type='list', default=[]), federatedIdentities=dict(type='list', default=[]), clientConsents=dict(type='list', default=[]), origin=dict(type='str'), state=dict(choices=["absent", "present"], default='present'), force=dict(type='bool', default=False), ) argument_spec.update(meta_args) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) result = dict(changed=False, msg='', user={}) # Obtain access token, initialize API try: connection_header = get_token( base_url=module.params.get('auth_keycloak_url'), validate_certs=module.params.get('validate_certs'), auth_realm=module.params.get('auth_realm'), client_id=module.params.get('auth_client_id'), auth_username=module.params.get('auth_username'), auth_password=module.params.get('auth_password'), client_secret=module.params.get('auth_client_secret'), ) 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') force = module.params.get('force') # Create a representation of the user received in parameters newUserRepresentation = {} newUserClientRolesRepresentation = {} newUserRepresentation["username"] = module.params.get('username') if module.params.get('self') is not None: newUserRepresentation["self"] = module.params.get('self') if module.params.get('id') is not None: newUserRepresentation["id"] = module.params.get('id') newUserRepresentation["enabled"] = module.params.get('enabled') newUserRepresentation["emailVerified"] = module.params.get('emailVerified') if module.params.get('firstName') is not None: newUserRepresentation["firstName"] = module.params.get('firstName') if module.params.get('lastName') is not None: newUserRepresentation["lastName"] = module.params.get('lastName') if module.params.get('email') is not None: newUserRepresentation["email"] = module.params.get('email') if module.params.get('federationLink') is not None: newUserRepresentation["federationLink"] = module.params.get( 'federationLink') if module.params.get('serviceAccountClientId') is not None: newUserRepresentation["serviceAccountClientId"] = module.params.get( 'serviceAccountClientId') if module.params.get('origin') is not None: newUserRepresentation["origin"] = module.params.get('origin') if module.params.get('credentials') is not None: newUserRepresentation["credentials"] = module.params.get('credentials') if module.params.get('disableableCredentialTypes') is not None: newUserRepresentation[ "disableableCredentialTypes"] = module.params.get( 'disableableCredentialTypes') if module.params.get('federatedIdentities') is not None: newUserRepresentation["federatedIdentities"] = module.params.get( 'federatedIdentities') if module.params.get('requiredActions') is not None: newUserRepresentation["requiredActions"] = module.params.get( 'requiredActions') if module.params.get('clientConsents') is not None: newUserRepresentation["clientConsents"] = module.params.get( 'clientConsents') if module.params.get('attributes') is not None: newUserRepresentation["attributes"] = module.params.get('attributes') if module.params.get('access') is not None: newUserRepresentation["access"] = module.params.get('access') if module.params.get('clientRoles') is not None: newUserClientRolesRepresentation["clientRoles"] = module.params.get( 'clientRoles') if module.params.get('realmRoles') is not None: newUserRepresentation["realmRoles"] = module.params.get('realmRoles') if module.params.get('groups') is not None: newUserRepresentation["groups"] = module.params.get('groups') changed = False userRepresentation = kc.search_user_by_username( username=newUserRepresentation["username"], realm=realm) if userRepresentation == {}: # The user does not exist # Create the user if (state == 'present'): # If state is present # Create the user userRepresentation = kc.create_user( newUserRepresentation=newUserRepresentation, realm=realm) # Add user ID to new representation newUserRepresentation['id'] = userRepresentation["id"] # Assign roles to user kc.assing_roles_to_user( user_id=newUserRepresentation["id"], userRealmRoles=newUserRepresentation['realmRoles'], userClientRoles=newUserClientRolesRepresentation[ 'clientRoles'], realm=realm) # set user groups kc.update_user_groups_membership( newUserRepresentation=newUserRepresentation, realm=realm) # Get the updated user realm roles userRepresentation["realmRoles"] = kc.get_user_realm_roles( user_id=userRepresentation["id"], realm=realm) # Get the user clientRoles userRepresentation["clientRoles"] = kc.get_user_client_roles( user_id=userRepresentation["id"], realm=realm) # Get the user groups userRepresentation["groups"] = kc.get_user_groups( user_id=userRepresentation["id"], realm=realm) changed = True result["user"] = userRepresentation elif state == 'absent': # Otherwise, the status is absent result["msg"] = 'User %s is absent' % ( newUserRepresentation["username"]) else: # the user already exists if (state == 'present'): # if desired state is present if force: # If the force option is set to true # Delete the existing user kc.delete_user(user_id=userRepresentation["id"], realm=realm) changed = True # Recreate the user userRepresentation = kc.create_user( newUserRepresentation=newUserRepresentation, realm=realm) # Add user ID to new representation newUserRepresentation['id'] = userRepresentation["id"] else: # If the force option is false excludes = [ "access", "notBefore", "createdTimestamp", "totp", "credentials", "disableableCredentialTypes", "realmRoles", "clientRoles", "groups", "clientConsents", "federatedIdentities", "requiredActions" ] # Add user ID to new representation newUserRepresentation['id'] = userRepresentation["id"] # Compare users if not ( isDictEquals(newUserRepresentation, userRepresentation, excludes) ): # If the new user does not introduce a change to the existing user # Update the user userRepresentation = kc.update_user( newUserRepresentation=newUserRepresentation, realm=realm) changed = True # Assign roles to user if kc.assing_roles_to_user( user_id=newUserRepresentation["id"], userRealmRoles=newUserRepresentation['realmRoles'], userClientRoles=newUserClientRolesRepresentation[ 'clientRoles'], realm=realm): changed = True # set user groups if kc.update_user_groups_membership( newUserRepresentation=newUserRepresentation, realm=realm): changed = True # Get the updated user realm roles userRepresentation["realmRoles"] = kc.get_user_realm_roles( user_id=userRepresentation["id"], realm=realm) # Get the user clientRoles userRepresentation["clientRoles"] = kc.get_user_client_roles( user_id=userRepresentation["id"], realm=realm) # Get the user groups userRepresentation["groups"] = kc.get_user_groups( user_id=userRepresentation["id"], realm=realm) result["user"] = userRepresentation elif state == 'absent': # Status is absent # Delete user kc.delete_user(user_id=userRepresentation['id'], realm=realm) result["msg"] = 'User %s deleted' % (userRepresentation['id']) changed = True result['changed'] = changed module.exit_json(**result)
def main(): """ Module execution :return: """ argument_spec = keycloak_argument_spec() protmapper_spec = dict( consentRequired=dict(type='bool'), consentText=dict(type='str'), id=dict(type='str'), name=dict(type='str'), protocol=dict(type='str', choices=['openid-connect', 'saml']), protocolMapper=dict(type='str'), config=dict(type='dict'), state=dict(type='str', choices=['absent', 'present'], default='present'), ) clientrolecomposites_spec = dict( name=dict(type='str'), id=dict(type='str'), ) clientroles_spec = dict( name=dict(type='str'), description=dict(type='str'), composite=dict(type='bool'), composites=dict(type='list', elements='dict', options=clientrolecomposites_spec), state=dict(type='str', choices=['absent', 'present'], default='present'), ) realmscopemappings_spec = dict(name=dict(type='str'), state=dict(type='str', choices=['absent', 'present'], default='present')) clientrolescopemappings_spec = dict(name=dict(type='str'), state=dict( type='str', choices=['absent', 'present'], default='present')) clientsscopemappings_spec = dict(id=dict(type='str'), roles=dict( type='list', options=clientrolescopemappings_spec)) scopemappings_spec = dict(realm=dict(type='list', options=realmscopemappings_spec), clients=dict(type='list', options=clientsscopemappings_spec)) meta_args = dict( state=dict(default='present', choices=['present', 'absent']), realm=dict(type='str', default='master'), id=dict(type='str'), client_id=dict(type='str', aliases=['clientId']), name=dict(type='str'), description=dict(type='str'), root_url=dict(type='str', aliases=['rootUrl']), admin_url=dict(type='str', aliases=['adminUrl']), base_url=dict(type='str', aliases=['baseUrl']), surrogate_auth_required=dict(type='bool', aliases=['surrogateAuthRequired']), enabled=dict(type='bool'), client_authenticator_type=dict(type='str', choices=['client-secret', 'client-jwt'], aliases=['clientAuthenticatorType']), secret=dict(type='str', no_log=True), registration_access_token=dict(type='str', aliases=['registrationAccessToken']), default_roles=dict(type='list', aliases=['defaultRoles']), redirect_uris=dict(type='list', aliases=['redirectUris']), web_origins=dict(type='list', aliases=['webOrigins']), not_before=dict(type='int', aliases=['notBefore']), bearer_only=dict(type='bool', aliases=['bearerOnly']), consent_required=dict(type='bool', aliases=['consentRequired']), standard_flow_enabled=dict(type='bool', aliases=['standardFlowEnabled']), implicit_flow_enabled=dict(type='bool', aliases=['implicitFlowEnabled']), direct_access_grants_enabled=dict( type='bool', aliases=['directAccessGrantsEnabled']), service_accounts_enabled=dict(type='bool', aliases=['serviceAccountsEnabled']), authorization_services_enabled=dict( type='bool', aliases=['authorizationServicesEnabled']), public_client=dict(type='bool', aliases=['publicClient']), frontchannel_logout=dict(type='bool', aliases=['frontchannelLogout']), protocol=dict(type='str', choices=['openid-connect', 'saml'], default='openid-connect'), attributes=dict(type='dict'), full_scope_allowed=dict(type='bool', aliases=['fullScopeAllowed']), node_re_registration_timeout=dict( type='int', aliases=['nodeReRegistrationTimeout']), registered_nodes=dict(type='dict', aliases=['registeredNodes']), client_template=dict(type='str', aliases=['clientTemplate']), use_template_config=dict(type='bool', aliases=['useTemplateConfig']), use_template_scope=dict(type='bool', aliases=['useTemplateScope']), use_template_mappers=dict(type='bool', aliases=['useTemplateMappers']), protocol_mappers=dict(type='list', elements='dict', options=protmapper_spec, aliases=['protocolMappers']), authorization_settings=dict(type='dict', aliases=['authorizationSettings']), client_roles=dict(type='list', elements='dict', options=clientroles_spec, aliases=['clientRoles', 'roles']), scope_mappings=dict(type='dict', aliases=['scopeMappings'], options=scopemappings_spec), force=dict(type='bool', default=False), ) argument_spec.update(meta_args) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['client_id', 'id']])) result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={}, clientSecret='') # Obtain access token, initialize API try: connection_header = get_token( base_url=module.params.get('auth_keycloak_url'), validate_certs=module.params.get('validate_certs'), auth_realm=module.params.get('auth_realm'), client_id=module.params.get('auth_client_id'), auth_username=module.params.get('auth_username'), auth_password=module.params.get('auth_password'), client_secret=module.params.get('auth_client_secret'), ) except KeycloakError as e: module.fail_json(msg=str(e)) kc = KeycloakAPI(module, connection_header) realm = module.params.get('realm') cid = module.params.get('id') state = module.params.get('state') # convert module parameters to client representation parameters (if they belong in there) client_params = [ x for x in module.params if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'url', 'force'] and module.params.get(x) is not None ] keycloak_argument_spec().keys() # See whether the client already exists in Keycloak if cid is None: before_client = kc.get_client_by_clientid( module.params.get('client_id'), realm=realm) if before_client is not None: cid = before_client['id'] else: before_client = kc.get_client_by_id(cid, realm=realm) if before_client is None: before_client = dict() # Build a proposed changeset from parameters given to this module changeset = dict() for client_param in client_params: new_param_value = module.params.get(client_param) # some lists in the Keycloak API are sorted, some are not. if isinstance(new_param_value, list): if client_param in ['attributes']: try: new_param_value = sorted(new_param_value) except TypeError: pass # Unfortunately, the ansible argument spec checker introduces variables with null values when # they are not specified if client_param == 'protocol_mappers': new_param_value = [ dict((k, v) for k, v in x.items() if x[k] is not None) for x in new_param_value ] if client_param == 'roles': client_param = 'client_roles' changeset[camel(client_param)] = new_param_value newClientScopeMappings = {} newClientScopeRealm = {} newClientScopeClients = {} if module.params.get('scope_mappings') is not None: newClientScopeMappings["scope_mappings"] = module.params.get( 'scope_mappings') if newClientScopeMappings["scope_mappings"]["realm"] is not None: newClientScopeRealm["realmRoles"] = newClientScopeMappings[ "scope_mappings"]["realm"] if newClientScopeMappings["scope_mappings"]["clients"] is not None: newClientScopeClients["clientRoles"] = newClientScopeMappings[ "scope_mappings"]["clients"] # Whether creating or updating a client, take the before-state and merge the changeset into it updated_client = before_client.copy() updated_client.update(changeset) result['proposed'] = sanitize_cr(changeset) result['existing'] = sanitize_cr(before_client) # If the client does not exist yet, before_client is still empty if before_client == dict(): if state == 'absent': # do nothing and exit if module._diff: result['diff'] = dict(before='', after='') result['msg'] = 'Client does not exist, doing nothing.' module.exit_json(**result) # create new client result['changed'] = True if 'clientId' not in updated_client: module.fail_json( msg='client_id needs to be specified when creating a new client' ) if module._diff: result['diff'] = dict(before='', after=sanitize_cr(updated_client)) if module.check_mode: module.exit_json(**result) kc.create_client(updated_client, realm=realm) after_client = kc.get_client_by_clientid(updated_client['clientId'], realm=realm) result['end_state'] = sanitize_cr(after_client) client_secret = kc.get_client_secret_by_id(after_client['id'], realm=realm) if client_secret is not None: result['clientSecret'] = client_secret if module.params.get('scope_mappings') is not None: kc.assing_scope_roles_to_client( client_id=after_client['id'], clientScopeRealmRoles=newClientScopeRealm["realmRoles"], clientScopeClientRoles=newClientScopeClients["clientRoles"], realm=realm) result['changed'] = True result[ 'msg'] = 'Client %s has been created.' % updated_client['clientId'] module.exit_json(**result) else: if state == 'present': # update existing client result['changed'] = True if module.check_mode: # We can only compare the current client with the proposed updates we have if module._diff: result['diff'] = dict(before=sanitize_cr(before_client), after=sanitize_cr(updated_client)) result['changed'] = (before_client != updated_client) module.exit_json(**result) kc.update_client(cid, updated_client, realm=realm) after_client = kc.get_client_by_id(cid, realm=realm) client_secret = kc.get_client_secret_by_id(cid, realm=realm) if client_secret is not None: result['clientSecret'] = client_secret if before_client == after_client: result['changed'] = False if module._diff: result['diff'] = dict(before=sanitize_cr(before_client), after=sanitize_cr(after_client)) if module.params.get('scope_mappings') is not None: result['changed'] = kc.assing_scope_roles_to_client( client_id=after_client['id'], clientScopeRealmRoles=newClientScopeRealm["realmRoles"], clientScopeClientRoles=newClientScopeClients[ "clientRoles"], realm=realm) result['end_state'] = sanitize_cr(after_client) result['msg'] = 'Client %s has been updated.' % updated_client[ 'clientId'] module.exit_json(**result) else: # Delete existing client result['changed'] = True if module._diff: result['diff']['before'] = sanitize_cr(before_client) result['diff']['after'] = '' if module.check_mode: module.exit_json(**result) kc.delete_client(cid, realm=realm) result['proposed'] = dict() result['end_state'] = dict() result['msg'] = 'Client %s has been deleted.' % before_client[ 'clientId'] module.exit_json(**result) module.exit_json(**result)
def main(): """ Module execution :return: """ argument_spec = keycloak_argument_spec() meta_args = dict( state=dict(default='present', choices=['present', 'absent']), realm=dict(default='master'), id=dict(type='str'), name=dict(type='str'), attributes=dict(type='dict'), path=dict(type='str'), attributes_list=dict(type='list'), realmRoles=dict(type='list'), clientRoles=dict(type='list'), syncLdapMappers=dict(type='bool', default=False), force=dict(type='bool', default=False), ) argument_spec.update(meta_args) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['id', 'name']])) result = dict(changed=False, msg='', diff={}, group='') # Obtain access token, initialize API try: connection_header = get_token( base_url=module.params.get('auth_keycloak_url'), validate_certs=module.params.get('validate_certs'), auth_realm=module.params.get('auth_realm'), client_id=module.params.get('auth_client_id'), auth_username=module.params.get('auth_username'), auth_password=module.params.get('auth_password'), client_secret=module.params.get('auth_client_secret'), ) 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') gid = module.params.get('id') name = module.params.get('name') attributes = module.params.get('attributes') # Add attribute received as a list to the attributes dict kc.add_attributes_list_to_attributes_dict( module.params.get('attributes_list'), attributes) syncLdapMappers = module.params.get('syncLdapMappers') groupRealmRoles = module.params.get('realmRoles') groupClientRoles = module.params.get('clientRoles') force = module.params.get('force') before_group = None # current state of the group, for merging. # Synchronize LDAP group to Keycloak if syncLdapMappers is true if syncLdapMappers: kc.sync_ldap_groups("fedToKeycloak", realm=realm) # does the group already exist? if gid is None: before_group = kc.get_group_by_name(name, realm=realm) else: before_group = kc.get_group_by_groupid(gid, realm=realm) before_group = {} if before_group is None else before_group # attributes in Keycloak have their values returned as lists # via the API. attributes is a dict, so we'll transparently convert # the values to lists. if attributes is not None: for key, val in module.params['attributes'].items(): module.params['attributes'][key] = [ val ] if not isinstance(val, list) else val excludes = [ 'state', 'realm', 'force', 'attributes_list', 'realmRoles', 'clientRoles', 'syncLdapMappers' ] group_params = [ x for x in module.params if x not in list(keycloak_argument_spec().keys()) + excludes and module.params.get(x) is not None ] # build a changeset changeset = {} for param in group_params: new_param_value = module.params.get(param) old_value = before_group[param] if param in before_group else None if new_param_value != old_value: changeset[camel(param)] = new_param_value # prepare the new group updated_group = before_group.copy() updated_group.update(changeset) # if before_group is none, the group doesn't exist. if before_group == {}: if state == 'absent': # nothing to do. if module._diff: result['diff'] = dict(before='', after='') result['msg'] = 'Group does not exist; doing nothing.' result['group'] = dict() module.exit_json(**result) # for 'present', create a new group. result['changed'] = True if name is None: module.fail_json( msg='name must be specified when creating a new group') if module._diff: result['diff'] = dict(before='', after=updated_group) if module.check_mode: module.exit_json(**result) # do it for real! kc.create_group(updated_group, realm=realm) # Assing roles to group kc.assing_roles_to_group(groupRepresentation=updated_group, groupRealmRoles=groupRealmRoles, groupClientRoles=groupClientRoles, realm=realm) # Sync Keycloak groups to User Storages if syncLdapMappers is true if syncLdapMappers: kc.sync_ldap_groups("keycloakToFed", realm=realm) after_group = kc.get_group_by_name(name, realm) result['group'] = after_group result['msg'] = 'Group {name} has been created with ID {id}'.format( name=after_group['name'], id=after_group['id']) else: if state == 'present': # no changes if updated_group == before_group and not force: result['changed'] = False result['group'] = updated_group result['msg'] = "No changes required to group {name}.".format( name=before_group['name']) module.exit_json(**result) # update the existing group result['changed'] = True if module._diff: result['diff'] = dict(before=before_group, after=updated_group) if module.check_mode: module.exit_json(**result) if force: # delete for real gid = before_group['id'] kc.delete_group(groupid=gid, realm=realm) # remove id del (updated_group['id']) if "realmRoles" in updated_group: del (updated_group['realmRoles']) if "clientRoles" in updated_group: del (updated_group['clientRoles']) # create it again kc.create_group(updated_group, realm=realm) else: # do the update kc.update_group(updated_group, realm=realm) # Assing roles to group kc.assing_roles_to_group(groupRepresentation=updated_group, groupRealmRoles=groupRealmRoles, groupClientRoles=groupClientRoles, realm=realm) # Sync Keycloak groups to User Storages if syncLdapMappers is true if syncLdapMappers: kc.sync_ldap_groups("keycloakToFed", realm=realm) if force: after_group = kc.get_group_by_name(name, realm) else: after_group = kc.get_group_by_groupid(updated_group['id'], realm=realm) result['group'] = after_group result['msg'] = "Group {id} has been updated".format( id=after_group['id']) module.exit_json(**result) elif state == 'absent': result['group'] = dict() if module._diff: result['diff'] = dict(before=before_group, after='') if module.check_mode: module.exit_json(**result) # delete for real gid = before_group['id'] kc.delete_group(groupid=gid, realm=realm) # Sync Keycloak groups to User Storages if syncLdapMappers is true if syncLdapMappers: kc.sync_ldap_groups("keycloakToFed", realm=realm) result['changed'] = True result['msg'] = "Group {name} has been deleted".format( name=before_group['name']) module.exit_json(**result) module.exit_json(**result)
def main(): """ Module execution :returm: """ argument_spec = keycloak_argument_spec() meta_args = dict( realm=dict(type='str', required=True), alias=dict(type='str', required=True), providerId=dict(type='str'), copyFrom=dict(type='str'), authenticationExecutions=dict(type='list'), state=dict(choices=["absent", "present"], default='present'), force=dict(type='bool', default=False), ) argument_spec.update(meta_args) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) result = dict(changed=False, msg='', flow={}) # Obtain access token, initialize API try: connection_header = get_token( base_url=module.params.get('auth_keycloak_url'), validate_certs=module.params.get('validate_certs'), auth_realm=module.params.get('auth_realm'), client_id=module.params.get('auth_client_id'), auth_username=module.params.get('auth_username'), auth_password=module.params.get('auth_password'), client_secret=module.params.get('auth_client_secret'), ) 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') force = module.params.get('force') newAuthenticationRepresentation = {} newAuthenticationRepresentation["alias"] = module.params.get("alias") newAuthenticationRepresentation["copyFrom"] = module.params.get("copyFrom") newAuthenticationRepresentation["providerId"] = module.params.get("providerId") newAuthenticationRepresentation["authenticationExecutions"] = module.params.get("authenticationExecutions") changed = False authenticationRepresentation = kc.get_authentication_flow_by_alias(alias=newAuthenticationRepresentation["alias"], realm=realm) if authenticationRepresentation == {}: # Authentication flow does not exist if (state == 'present'): # If desired state is prenset # If copyFrom is defined, create authentication flow from a copy if "copyFrom" in newAuthenticationRepresentation and newAuthenticationRepresentation["copyFrom"] is not None: authenticationRepresentation = kc.copy_auth_flow(config=newAuthenticationRepresentation, realm=realm) else: # Create an empty authentication flow authenticationRepresentation = kc.create_empty_auth_flow(config=newAuthenticationRepresentation, realm=realm) # If the authentication still not exist on the server, raise an exception. if authenticationRepresentation is None: result['msg'] = "Authentication just created not found: " + str(newAuthenticationRepresentation) module.fail_json(**result) # Configure the executions for the flow kc.create_or_update_executions(config=newAuthenticationRepresentation, realm=realm) changed = True # Get executions created executionsRepresentation = kc.get_executions_representation(config=newAuthenticationRepresentation, realm=realm) if executionsRepresentation is not None: authenticationRepresentation["authenticationExecutions"] = executionsRepresentation result['changed'] = changed result['flow'] = authenticationRepresentation elif state == 'absent': # If desired state is absent. result['msg'] = newAuthenticationRepresentation["alias"] + ' absent' else: # The authentication flow already exist if (state == 'present'): # if desired state is present if force: # If force option is true # Delete the actual authentication flow kc.delete_authentication_flow_by_id(id=authenticationRepresentation["id"], realm=realm) changed = True # If copyFrom is defined, create authentication flow from a copy if "copyFrom" in newAuthenticationRepresentation and newAuthenticationRepresentation["copyFrom"] is not None: authenticationRepresentation = kc.copy_auth_flow(config=newAuthenticationRepresentation, realm=realm) else: # Create an empty authentication flow authenticationRepresentation = kc.create_empty_auth_flow(config=newAuthenticationRepresentation, realm=realm) # If the authentication still not exist on the server, raise an exception. if authenticationRepresentation is None: result['msg'] = "Authentication just created not found: " + str(newAuthenticationRepresentation) result['changed'] = changed module.fail_json(**result) # Configure the executions for the flow if kc.create_or_update_executions(config=newAuthenticationRepresentation, realm=realm): changed = True # Get executions created executionsRepresentation = kc.get_executions_representation(config=newAuthenticationRepresentation, realm=realm) if executionsRepresentation is not None: authenticationRepresentation["authenticationExecutions"] = executionsRepresentation result['flow'] = authenticationRepresentation result['changed'] = changed elif state == 'absent': # If desired state is absent # Delete the authentication flow alias. kc.delete_authentication_flow_by_id(id=authenticationRepresentation["id"], realm=realm) changed = True result['msg'] = 'Authentication flow: ' + newAuthenticationRepresentation['alias'] + ' id: ' + authenticationRepresentation["id"] + ' is deleted' result['changed'] = changed module.exit_json(**result)
def main(): argument_spec = keycloak_argument_spec() composites_spec = dict(name=dict(type='str', required=True), clientId=dict(type='str')) meta_args = dict( realm=dict(type='str', default='master'), name=dict(type='str', required=True), description=dict(type='str', default=None), composite=dict(type='bool', default=False), clientRole=dict(type='bool', default=False), containerId=dict(type='str', required=False), composites=dict(type='list', default=[], options=composites_spec), state=dict(choices=["absent", "present"], default='present'), force=dict(type='bool', default=False), ) argument_spec.update(meta_args) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) result = dict(changed=False, msg='', role={}, composites=None) # Obtain access token, initialize API try: connection_header = get_token( base_url=module.params.get('auth_keycloak_url'), validate_certs=module.params.get('validate_certs'), auth_realm=module.params.get('auth_realm'), client_id=module.params.get('auth_client_id'), auth_username=module.params.get('auth_username'), auth_password=module.params.get('auth_password'), client_secret=module.params.get('auth_client_secret'), ) 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') force = module.params.get('force') newComposites = None # Create representation for the new role newRoleRepresentation = {} newRoleRepresentation["name"] = module.params.get('name') if module.params.get('description') is not None: newRoleRepresentation["description"] = module.params.get('description') newRoleRepresentation["composite"] = module.params.get('composite') newRoleRepresentation["clientRole"] = module.params.get('clientRole') newRoleRepresentation["containerId"] = module.params.get( 'containerId') if module.params.get( 'containerId') is not None else realm if module.params.get('composites') is not None: newComposites = module.params.get('composites') changed = False # Search the role on Keycloak server. roleRepresentation = kc.search_realm_role_by_name( name=newRoleRepresentation["name"], realm=realm) if roleRepresentation == {}: # If role does not exists if (state == 'present'): # If desired state is present # Create Role kc.create_realm_role(newRoleRepresentation=newRoleRepresentation, realm=realm) # Create composites kc.create_or_update_realm_role_composites( newComposites=newComposites, newRoleRepresentation=newRoleRepresentation, realm=realm) # Get created role roleRepresentation = kc.get_realm_role( name=newRoleRepresentation["name"], realm=realm) # Get created composites composites = kc.get_realm_role_composites_with_client_id( name=newRoleRepresentation["name"], realm=realm) changed = True result['role'] = roleRepresentation result['composites'] = composites elif state == 'absent': # If desired state is absent result["msg"] = "Realm role %s is absent in realm %s" % ( newRoleRepresentation["name"], realm) else: # If role already exists if (state == 'present'): # If desired state is present if force: # If force option is true # Delete the existing role kc.delete_realm_role(name=roleRepresentation["name"], realm=realm) # Create role again kc.create_realm_role( newRoleRepresentation=newRoleRepresentation, realm=realm) changed = True else: # If force option is false # Compare roles if not (isDictEquals( newRoleRepresentation, roleRepresentation)): # If new role introduce changes # Update the role kc.update_realm_role( newRoleRepresentation=newRoleRepresentation, realm=realm) changed = True # Manage composites if kc.create_or_update_realm_role_composites( newComposites=newComposites, newRoleRepresentation=newRoleRepresentation, realm=realm): changed = True # Get created role roleRepresentation = kc.get_realm_role( name=newRoleRepresentation["name"], realm=realm) # Get composites composites = kc.get_realm_role_composites_with_client_id( name=newRoleRepresentation["name"], realm=realm) result["role"] = roleRepresentation result["composites"] = composites elif state == 'absent': # If desired state is absent # Delete role kc.delete_realm_role(name=newRoleRepresentation["name"], realm=realm) changed = True result["msg"] = "Realm role %s is deleted in realm %s" % ( newRoleRepresentation["name"], realm) result['changed'] = changed module.exit_json(**result)
def main(): argument_spec = keycloak_argument_spec() smtp_spec = { "replyToDisplayName": { "type": "str" }, "starttls": { "type": "str", "choices": ["true", "false"], "default": "false" }, "auth": { "type": "str", "choices": ["true", "false"], "default": "false" }, "port": { "type": "str", "default": "25" }, "host": { "type": "str" }, "replyTo": { "type": "str" }, "from": { "type": "str" }, "fromDisplayName": { "type": "str" }, "envelopeFrom": { "type": "str" }, "ssl": { "type": "str", "choices": ["true", "false"], "default": "false" }, "user": { "type": "str" }, "password": { "type": "str", "no_log": True } } eventconfig_spec = { "eventsEnabled": { "type": "bool" }, "eventsListeners": { "type": "list" }, "adminEventsEnabled": { "type": "bool" }, "adminEventsDetailsEnabled": { "type": "bool" }, "eventsExpiration": { "type": "int" }, "enabledEventTypes": { "type": "list", "choices": [ "SEND_RESET_PASSWORD", "UPDATE_TOTP", "REMOVE_TOTP", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_PASSWORD_ERROR", "REGISTER", "LOGOUT", "CLIENT_REGISTER", "UPDATE_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "IDENTITY_PROVIDER_FIRST_LOGIN", "VERIFY_EMAIL", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "IDENTITY_PROVIDER_POST_LOGIN", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "SEND_VERIFY_EMAIL_ERROR", "SEND_IDENTITY_PROVIDER_LINK", "RESET_PASSWORD", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ] } } meta_args = dict( realm=dict(type='str', default='master'), displayName=dict(type='str', required=True, aliases=['name']), displayNameHtml=dict(type='str', default="", aliases=['namehtml']), loginTheme=dict(type="str"), adminTheme=dict(type="str"), emailTheme=dict(type="str"), accountTheme=dict(type="str"), internationalizationEnabled=dict(type="bool"), supportedLocales=dict(type="list"), defaultLocale=dict(type="str"), accessCodeLifespan=dict(type='int', default=60), accessCodeLifespanLogin=dict(type='int', default=1800), accessCodeLifespanUserAction=dict(type='int', default=300), notBefore=dict(type='int', default=0), revokeRefreshToken=dict(type='bool', default=False), accessTokenLifespan=dict(type='int', default=300), accessTokenLifespanForImplicitFlow=dict(type='int', default=900), ssoSessionIdleTimeout=dict(type='int', default=1800), ssoSessionMaxLifespan=dict(type='int', default=36000), offlineSessionIdleTimeout=dict(type='int', default=2592000), enabled=dict(type='bool', default=True), sslRequired=dict(type='str', default="external"), registrationAllowed=dict(type='bool', default=False), registrationEmailAsUsername=dict(type='bool', default=False), rememberMe=dict(type='bool', default=False), verifyEmail=dict(type='bool', default=False), loginWithEmailAllowed=dict(type='bool', default=True), duplicateEmailsAllowed=dict(type='bool', default=False), resetPasswordAllowed=dict(type='bool', default=False), editUsernameAllowed=dict(type='bool', default=False), bruteForceProtected=dict(type='bool', default=False), permanentLockout=dict(type='bool', default=False), maxFailureWaitSeconds=dict(type='int', default=900), minimumQuickLoginWaitSeconds=dict(type='int', default=60), waitIncrementSeconds=dict(type='int', default=60), quickLoginCheckMilliSeconds=dict(type='int', default=1000), maxDeltaTimeSeconds=dict(type='int', default=43200), failureFactor=dict(type='int', default=30), defaultRoles=dict(type='list', default=["offline_access", "uma_authorization"]), requiredCredentials=dict(type='list', default=["password"]), passwordPolicy=dict(type='str', default="hashIterations(20000)"), otpPolicyType=dict(type='str', default="totp"), otpPolicyAlgorithm=dict(type='str', default="HmacSHA1"), otpPolicyInitialCounter=dict(type='int', default=0), otpPolicyDigits=dict(type='int', default=6), otpPolicyLookAheadWindow=dict(type='int', default=1), otpPolicyPeriod=dict(type='int', default=30), smtpServer=dict(type='dict', default={}, options=smtp_spec), eventsConfig=dict(type='dict', options=eventconfig_spec), browserFlow=dict(type='str', default="browser"), registrationFlow=dict(type='str', default="registration"), directGrantFlow=dict(type='str', default="direct grant"), resetCredentialsFlow=dict(type='str', default="reset credentials"), clientAuthenticationFlow=dict(type='str', default="clients"), state=dict(choices=["absent", "present"], default='present'), force=dict(type='bool', default=False), attributes=dict(type='dict', default=None), browserSecurityHeaders=dict(type='dict', default=None)) argument_spec.update(meta_args) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) result = dict(changed=False, msg='', realm={}, eventsConfig={}) # Obtain access token, initialize API try: connection_header = get_token( base_url=module.params.get('auth_keycloak_url'), validate_certs=module.params.get('validate_certs'), auth_realm=module.params.get('auth_realm'), client_id=module.params.get('auth_client_id'), auth_username=module.params.get('auth_username'), auth_password=module.params.get('auth_password'), client_secret=module.params.get('auth_client_secret'), ) except KeycloakError as e: module.fail_json(msg=str(e)) kc = KeycloakAPI(module, connection_header) defaultAttributes = dict( _browser_header=dict(contentSecurityPolicy=dict( type='unicode', default="frame-src 'self'"), xContentTypeOptions=dict(type='unicode', default="nosniff"), xFrameOptions=dict(type='unicode', default="SAMEORIGIN"), xRobotsTag=dict(type='unicode', default="none"), xXSSProtection=dict(type='unicode', default="1; mode=block")), actionTokenGeneratedByAdminLifespan=dict(type='int', default=43200), actionTokenGeneratedByUserLifespan=dict(type='int', default=300), displayName=dict(type='unicode', default=module.params.get('name')), displayNameHtml=dict(type='unicode', default=module.params.get('namehtml')), ) defaultBrowserSecurityHeaders = dict( contentSecurityPolicy=dict(type='unicode', default="frame-src 'self'"), xContentTypeOptions=dict(type='unicode', default="nosniff"), xFrameOptions=dict(type='unicode', default="SAMEORIGIN"), xRobotsTag=dict(type='unicode', default="none"), xXSSProtection=dict(type='unicode', default="1; mode=block")) state = module.params.get('state') force = module.params.get('force') # Create a realm representation form module parameters newRealmRepresentation = {} newRealmRepresentation["id"] = module.params.get('realm') newRealmRepresentation["realm"] = module.params.get('realm') newRealmRepresentation["displayName"] = module.params.get('displayName') newRealmRepresentation["displayNameHtml"] = module.params.get( 'displayNameHtml') if module.params.get("loginTheme") is not None: newRealmRepresentation["loginTheme"] = module.params.get("loginTheme") if module.params.get("adminTheme") is not None: newRealmRepresentation["adminTheme"] = module.params.get("adminTheme") if module.params.get("emailTheme") is not None: newRealmRepresentation["emailTheme"] = module.params.get("emailTheme") if module.params.get("accountTheme") is not None: newRealmRepresentation["accountTheme"] = module.params.get( "accountTheme") newRealmRepresentation["accessCodeLifespan"] = module.params.get( 'accessCodeLifespan') newRealmRepresentation["accessCodeLifespanLogin"] = module.params.get( 'accessCodeLifespanLogin') newRealmRepresentation["accessCodeLifespanUserAction"] = module.params.get( 'accessCodeLifespanUserAction') newRealmRepresentation["notBefore"] = module.params.get('notBefore') newRealmRepresentation["revokeRefreshToken"] = module.params.get( 'revokeRefreshToken') newRealmRepresentation["accessTokenLifespan"] = module.params.get( 'accessTokenLifespan') newRealmRepresentation[ "accessTokenLifespanForImplicitFlow"] = module.params.get( 'accessTokenLifespanForImplicitFlow') newRealmRepresentation["ssoSessionIdleTimeout"] = module.params.get( 'ssoSessionIdleTimeout') newRealmRepresentation["ssoSessionMaxLifespan"] = module.params.get( 'ssoSessionMaxLifespan') newRealmRepresentation["offlineSessionIdleTimeout"] = module.params.get( 'offlineSessionIdleTimeout') newRealmRepresentation["enabled"] = module.params.get('enabled') newRealmRepresentation["sslRequired"] = module.params.get('sslRequired') newRealmRepresentation["registrationAllowed"] = module.params.get( 'registrationAllowed') newRealmRepresentation["registrationEmailAsUsername"] = module.params.get( 'registrationEmailAsUsername') newRealmRepresentation["rememberMe"] = module.params.get('rememberMe') newRealmRepresentation["verifyEmail"] = module.params.get('verifyEmail') newRealmRepresentation["loginWithEmailAllowed"] = module.params.get( 'loginWithEmailAllowed') newRealmRepresentation["duplicateEmailsAllowed"] = module.params.get( 'duplicateEmailsAllowed') newRealmRepresentation["resetPasswordAllowed"] = module.params.get( 'resetPasswordAllowed') newRealmRepresentation["editUsernameAllowed"] = module.params.get( 'editUsernameAllowed') newRealmRepresentation["bruteForceProtected"] = module.params.get( 'bruteForceProtected') newRealmRepresentation["permanentLockout"] = module.params.get( 'permanentLockout') newRealmRepresentation["maxFailureWaitSeconds"] = module.params.get( 'maxFailureWaitSeconds') newRealmRepresentation["minimumQuickLoginWaitSeconds"] = module.params.get( 'minimumQuickLoginWaitSeconds') newRealmRepresentation["waitIncrementSeconds"] = module.params.get( 'waitIncrementSeconds') newRealmRepresentation["quickLoginCheckMilliSeconds"] = module.params.get( 'quickLoginCheckMilliSeconds') newRealmRepresentation["maxDeltaTimeSeconds"] = module.params.get( 'maxDeltaTimeSeconds') newRealmRepresentation["failureFactor"] = module.params.get( 'failureFactor') newRealmRepresentation["defaultRoles"] = module.params.get('defaultRoles') newRealmRepresentation["requiredCredentials"] = module.params.get( 'requiredCredentials') newRealmRepresentation["passwordPolicy"] = module.params.get( 'passwordPolicy') newRealmRepresentation["otpPolicyType"] = module.params.get( 'otpPolicyType') newRealmRepresentation["otpPolicyAlgorithm"] = module.params.get( 'otpPolicyAlgorithm') newRealmRepresentation["otpPolicyInitialCounter"] = module.params.get( 'otpPolicyInitialCounter') newRealmRepresentation["otpPolicyDigits"] = module.params.get( 'otpPolicyDigits') newRealmRepresentation["otpPolicyLookAheadWindow"] = module.params.get( 'otpPolicyLookAheadWindow') newRealmRepresentation["otpPolicyPeriod"] = module.params.get( 'otpPolicyPeriod') newRealmRepresentation["smtpServer"] = module.params.get('smtpServer') remove_arguments_with_value_none(newRealmRepresentation["smtpServer"]) if module.params.get("supportedLocales") is not None: if module.params.get("internationalizationEnabled") is not None: newRealmRepresentation[ "internationalizationEnabled"] = module.params.get( "internationalizationEnabled") else: newRealmRepresentation["internationalizationEnabled"] = True newRealmRepresentation["supportedLocales"] = module.params.get( "supportedLocales") if module.params.get("defaultLocale") is not None: newRealmRepresentation["defaultLocale"] = module.params.get( "defaultLocale") else: newRealmRepresentation["internationalizationEnabled"] = False newRealmRepresentation["browserFlow"] = module.params.get('browserFlow') newRealmRepresentation["registrationFlow"] = module.params.get( 'registrationFlow') newRealmRepresentation["directGrantFlow"] = module.params.get( 'directGrantFlow') newRealmRepresentation["resetCredentialsFlow"] = module.params.get( 'resetCredentialsFlow') newRealmRepresentation["clientAuthenticationFlow"] = module.params.get( 'clientAuthenticationFlow') if module.params.get("eventsExpiration") is not None: newRealmRepresentation["eventsExpiration"] = module.params.get( 'eventsExpiration') # Read Events configuration for the Realm newEventsConfig = module.params.get("eventsConfig") remove_arguments_with_value_none(newEventsConfig) if module.params.get("browserSecurityHeaders") is not None: newRealmRepresentation["browserSecurityHeaders"] = module.params.get( "browserSecurityHeaders") changed = False # Find realm on Keycloak server realmRepresentation = kc.search_realm( realm=newRealmRepresentation["realm"]) if realmRepresentation == {}: # Realm does not exist if (state == 'present'): # If desired state is present # Create the realm result["realm"] = kc.create_realm( newRealmRepresentation=newRealmRepresentation) if newEventsConfig is not None: eventsConfig = kc.update_realm_events_config( realm=newRealmRepresentation["realm"], newEventsConfig=newEventsConfig) result["eventsConfig"] = eventsConfig changed = True else: # if desired state is absent result['msg'] = 'Realm %s is absent' % ( newRealmRepresentation["realm"]) else: # Realm already exists if (state == 'present'): # If desired state is present if force: # If force option is true # Delete the existing realm kc.delete_realm(newRealmRepresentation["realm"]) # Create realm realmRepresentation = kc.create_realm( newRealmRepresentation=newRealmRepresentation) changed = True else: # If force option is false # Compare realms if not isDictEquals(newRealmRepresentation, realmRepresentation ): # If new realm introduces changes # Update REALM realmRepresentation = kc.update_realm( newRealmRepresentation=newRealmRepresentation) changed = True else: realmRepresentation = kc.get_realm( realm=newRealmRepresentation["realm"]) if newEventsConfig is not None: # If there is event configuration # Get the existing events config eventsConfig = kc.get_realm_events_config( realm=newRealmRepresentation["realm"]) if not isDictEquals(newEventsConfig, eventsConfig): # If realm needs changed # Update event config eventsConfig = kc.update_realm_events_config( realm=newRealmRepresentation["realm"], newEventsConfig=newEventsConfig) result["eventsConfig"] = eventsConfig result["realm"] = realmRepresentation else: # If desired state is absent # Delete Realm kc.delete_realm(newRealmRepresentation["realm"]) changed = True result["msg"] = 'Realm %s deleted' % ( newRealmRepresentation["realm"]) result["changed"] = changed module.exit_json(**result)