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'),
    )

    meta_args = dict(
        realm=dict(type='str', default='master'),
        state=dict(default='present', choices=['present', 'absent']),
        id=dict(type='str'),
        name=dict(type='str'),
        description=dict(type='str'),
        protocol=dict(type='str', choices=['openid-connect', 'saml']),
        attributes=dict(type='dict'),
        full_scope_allowed=dict(type='bool'),
        protocol_mappers=dict(type='list',
                              elements='dict',
                              options=protmapper_spec),
    )
    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={},
                  proposed={},
                  existing={},
                  end_state={})

    # 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')
    cid = module.params.get('id')

    # convert module parameters to client representation parameters (if they belong in there)
    clientt_params = [
        x for x in module.params if x not in [
            'state', 'auth_keycloak_url', 'auth_client_id', 'auth_realm',
            'auth_client_secret', 'auth_username', 'auth_password',
            'validate_certs', 'realm'
        ] and module.params.get(x) is not None
    ]

    # See whether the client template already exists in Keycloak
    if cid is None:
        before_clientt = kc.get_client_template_by_name(
            module.params.get('name'), realm=realm)
        if before_clientt is not None:
            cid = before_clientt['id']
    else:
        before_clientt = kc.get_client_template_by_id(cid, realm=realm)

    if before_clientt is None:
        before_clientt = dict()

    result['existing'] = before_clientt

    # Build a proposed changeset from parameters given to this module
    changeset = dict()

    for clientt_param in clientt_params:
        # lists in the Keycloak API are sorted
        new_param_value = module.params.get(clientt_param)
        if isinstance(new_param_value, list):
            try:
                new_param_value = sorted(new_param_value)
            except TypeError:
                pass
        changeset[camel(clientt_param)] = new_param_value

    # Whether creating or updating a client, take the before-state and merge the changeset into it
    updated_clientt = before_clientt.copy()
    updated_clientt.update(changeset)

    result['proposed'] = changeset

    # If the client template does not exist yet, before_client is still empty
    if before_clientt == dict():
        if state == 'absent':
            # do nothing and exit
            if module._diff:
                result['diff'] = dict(before='', after='')
            result['msg'] = 'Client template does not exist, doing nothing.'
            module.exit_json(**result)

        # create new client template
        result['changed'] = True
        if 'name' not in updated_clientt:
            module.fail_json(
                msg='name needs to be specified when creating a new client')

        if module._diff:
            result['diff'] = dict(before='', after=updated_clientt)

        if module.check_mode:
            module.exit_json(**result)

        kc.create_client_template(updated_clientt, realm=realm)
        after_clientt = kc.get_client_template_by_name(updated_clientt['name'],
                                                       realm=realm)

        result['end_state'] = after_clientt

        result[
            'msg'] = 'Client template %s has been created.' % updated_clientt[
                'name']
        module.exit_json(**result)
    else:
        if state == 'present':
            # update existing client template
            result['changed'] = True
            if module.check_mode:
                # We can only compare the current client template with the proposed updates we have
                if module._diff:
                    result['diff'] = dict(before=before_clientt,
                                          after=updated_clientt)

                module.exit_json(**result)

            kc.update_client_template(cid, updated_clientt, realm=realm)

            after_clientt = kc.get_client_template_by_id(cid, realm=realm)
            if before_clientt == after_clientt:
                result['changed'] = False
            if module._diff:
                result['diff'] = dict(before=before_clientt,
                                      after=after_clientt)
            result['end_state'] = after_clientt

            result[
                'msg'] = 'Client template %s has been updated.' % updated_clientt[
                    'name']
            module.exit_json(**result)
        else:
            # Delete existing client
            result['changed'] = True
            if module._diff:
                result['diff']['before'] = before_clientt
                result['diff']['after'] = ''

            if module.check_mode:
                module.exit_json(**result)

            kc.delete_client_template(cid, realm=realm)
            result['proposed'] = dict()
            result['end_state'] = dict()
            result[
                'msg'] = 'Client template %s has been deleted.' % before_clientt[
                    'name']
            module.exit_json(**result)

    module.exit_json(**result)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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'),
    )

    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']),
        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']),
    )
    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={})

    # 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'] 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
            ]

        changeset[camel(client_param)] = new_param_value

    # 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)

        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)
            if before_client == after_client:
                result['changed'] = False
            if module._diff:
                result['diff'] = dict(before=sanitize_cr(before_client),
                                      after=sanitize_cr(after_client))
            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)