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'), gid=dict(type='str'), group_name=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' ]]), 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') gid = module.params.get('gid') group_name = module.params.get('group_name') roles = module.params.get('roles') # Check the parameters if cid is None and client_id is None: module.fail_json( msg='Either the `client_id` or `cid` has to be specified.') if gid is None and group_name is None: module.fail_json( msg='Either the `group_name` or `gid` has to be specified.') # Get the potential missing parameters if gid is None: group_rep = kc.get_group_by_name(group_name, realm=realm) if group_rep is not None: gid = group_rep['id'] else: module.fail_json(msg='Could not fetch group %s:' % group_name) if cid is None: cid = kc.get_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['name'] is None and role['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['id'] is None: role_id = kc.get_client_role_by_name(gid, 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'] 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) 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['name'] == available_role['name']: update_roles.append({ 'id': role['id'], 'name': role['name'], }) # Fetch roles to remove if state absent else: for assigned_role in assigned_roles_before: if role['name'] == assigned_role['name']: update_roles.append({ 'id': role['id'], 'name': role['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_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) 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_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) 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 with group %s.' % ( roles, group_name) 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')) 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') before_group = None # current state of the group, for merging. # 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 group_params = [ x for x in module.params if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm'] 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) 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: 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) # do the update kc.update_group(updated_group, realm=realm) 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) 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 :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'), ) argument_spec.update(meta_args) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['id', 'name'], [ 'token', 'auth_realm', 'auth_username', 'auth_password' ]]), required_together=([['auth_realm', 'auth_username', 'auth_password']])) result = dict(changed=False, msg='', diff={}, group='') # 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') gid = module.params.get('id') name = module.params.get('name') attributes = module.params.get('attributes') # 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 # Filter and map the parameters names that apply to the group group_params = [ x for x in module.params if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm'] and module.params.get(x) is not None ] # See if it already exists in Keycloak 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) if before_group is None: before_group = {} # Build a proposed changeset from parameters given to this module 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 desired values using the existing values (non-existence results in a dict that is save to use as a basis) desired_group = before_group.copy() desired_group.update(changeset) # Cater for when it doesn't exist (an empty dict) if not before_group: if state == 'absent': # Do nothing and exit if module._diff: result['diff'] = dict(before='', after='') result['changed'] = False result['end_state'] = {} result['group'] = result['end_state'] result['msg'] = 'Group does not exist; doing nothing.' module.exit_json(**result) # Process a creation 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=desired_group) if module.check_mode: module.exit_json(**result) # create it kc.create_group(desired_group, realm=realm) after_group = kc.get_group_by_name(name, realm) result['end_state'] = after_group result['group'] = result['end_state'] result['msg'] = 'Group {name} has been created with ID {id}'.format( name=after_group['name'], id=after_group['id']) module.exit_json(**result) else: if state == 'present': # Process an update # no changes if desired_group == before_group: result['changed'] = False result['end_state'] = desired_group result['group'] = result['end_state'] result['msg'] = "No changes required to group {name}.".format( name=before_group['name']) module.exit_json(**result) # doing an update result['changed'] = True if module._diff: result['diff'] = dict(before=before_group, after=desired_group) if module.check_mode: module.exit_json(**result) # do the update kc.update_group(desired_group, realm=realm) after_group = kc.get_group_by_groupid(desired_group['id'], realm=realm) result['end_state'] = after_group result['group'] = result['end_state'] result['msg'] = "Group {id} has been updated".format( id=after_group['id']) module.exit_json(**result) else: # Process a deletion (because state was not 'present') result['changed'] = True if module._diff: result['diff'] = dict(before=before_group, after='') if module.check_mode: module.exit_json(**result) # delete it gid = before_group['id'] kc.delete_group(groupid=gid, realm=realm) result['end_state'] = {} result['group'] = result['end_state'] result['msg'] = "Group {name} has been deleted".format( name=before_group['name']) module.exit_json(**result)