Beispiel #1
0
def main():
    """
    Module execution

    :return:
    """
    argument_spec = keycloak_argument_spec()

    mapper_spec = dict(
        id=dict(type='str'),
        name=dict(type='str'),
        identityProviderAlias=dict(type='str'),
        identityProviderMapper=dict(type='str'),
        config=dict(type='dict'),
    )

    meta_args = dict(
        state=dict(type='str',
                   default='present',
                   choices=['present', 'absent']),
        realm=dict(type='str', default='master'),
        alias=dict(type='str', required=True),
        add_read_token_role_on_create=dict(
            type='bool', aliases=['addReadTokenRoleOnCreate']),
        authenticate_by_default=dict(type='bool',
                                     aliases=['authenticateByDefault']),
        config=dict(type='dict'),
        display_name=dict(type='str', aliases=['displayName']),
        enabled=dict(type='bool'),
        first_broker_login_flow_alias=dict(
            type='str', aliases=['firstBrokerLoginFlowAlias']),
        link_only=dict(type='bool', aliases=['linkOnly']),
        post_broker_login_flow_alias=dict(type='str',
                                          aliases=['postBrokerLoginFlowAlias'
                                                   ]),
        provider_id=dict(type='str', aliases=['providerId']),
        store_token=dict(type='bool', aliases=['storeToken']),
        trust_email=dict(type='bool', aliases=['trustEmail']),
        mappers=dict(type='list', elements='dict', options=mapper_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')
    alias = module.params.get('alias')
    state = module.params.get('state')

    # convert module parameters to client representation parameters (if they belong in there)
    idp_params = [
        x for x in module.params
        if x not in list(keycloak_argument_spec().keys()) +
        ['state', 'realm', 'mappers'] and module.params.get(x) is not None
    ]

    # does the identity provider already exist?
    before_idp = get_identity_provider_with_mappers(kc, alias, realm)

    # build a changeset
    changeset = dict()

    for param in idp_params:
        new_param_value = module.params.get(param)
        old_value = before_idp[camel(param)] if camel(
            param) in before_idp else None
        if new_param_value != old_value:
            changeset[camel(param)] = new_param_value

    # special handling of mappers list to allow change detection
    changeset['mappers'] = before_idp.get('mappers', list())
    if module.params.get('mappers') is not None:
        for new_mapper in module.params.get('mappers'):
            old_mapper = next((x for x in changeset['mappers']
                               if x['name'] == new_mapper['name']), None)
            new_mapper = dict((k, v) for k, v in new_mapper.items()
                              if new_mapper[k] is not None)
            if old_mapper is not None:
                old_mapper.update(new_mapper)
            else:
                changeset['mappers'].append(new_mapper)
        # remove mappers if not present in module params
        changeset['mappers'] = [
            x for x in changeset['mappers'] if [
                y for y in module.params.get('mappers', [])
                if y['name'] == x['name']
            ] != []
        ]

    # prepare the new representation
    updated_idp = before_idp.copy()
    updated_idp.update(changeset)

    result['proposed'] = sanitize(changeset)
    result['existing'] = sanitize(before_idp)

    # if before_idp is none, the identity provider doesn't exist.
    if before_idp == dict():
        if state == 'absent':
            # nothing to do.
            if module._diff:
                result['diff'] = dict(before='', after='')
            result['changed'] = False
            result['end_state'] = dict()
            result['msg'] = 'Identity provider does not exist; doing nothing.'
            module.exit_json(**result)

        # for 'present', create a new identity provider.
        result['changed'] = True

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

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

        # do it for real!
        updated_idp = updated_idp.copy()
        mappers = updated_idp.pop('mappers', [])
        kc.create_identity_provider(updated_idp, realm)
        for mapper in mappers:
            kc.create_identity_provider_mapper(mapper, alias, realm)
        after_idp = get_identity_provider_with_mappers(kc, alias, realm)

        result['end_state'] = sanitize(after_idp)

        result['msg'] = 'Identity provider {alias} has been created'.format(
            alias=alias)
        module.exit_json(**result)

    else:
        if state == 'present':
            # no changes
            if updated_idp == before_idp:
                result['changed'] = False
                result['end_state'] = sanitize(updated_idp)
                result[
                    'msg'] = "No changes required to identity provider {alias}.".format(
                        alias=alias)
                module.exit_json(**result)

            # update the existing role
            result['changed'] = True

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

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

            # do the update
            updated_idp = updated_idp.copy()
            updated_mappers = updated_idp.pop('mappers', [])
            kc.update_identity_provider(updated_idp, realm)
            for mapper in updated_mappers:
                if mapper.get('id') is not None:
                    kc.update_identity_provider_mapper(mapper, alias, realm)
                else:
                    kc.create_identity_provider_mapper(mapper, alias, realm)
            for mapper in [
                    x for x in before_idp['mappers']
                    if [y for y in updated_mappers
                        if y["name"] == x['name']] == []
            ]:
                kc.delete_identity_provider_mapper(mapper['id'], alias, realm)

            after_idp = get_identity_provider_with_mappers(kc, alias, realm)

            result['end_state'] = sanitize(after_idp)

            result[
                'msg'] = "Identity provider {alias} has been updated".format(
                    alias=alias)
            module.exit_json(**result)

        elif state == 'absent':
            result['changed'] = True

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

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

            # delete for real
            kc.delete_identity_provider(alias, realm)

            result['end_state'] = dict()

            result[
                'msg'] = "Identity provider {alias} has been deleted".format(
                    alias=alias)
            module.exit_json(**result)

    module.exit_json(**result)
def main():
    """
    Module execution

    :return:
    """
    argument_spec = keycloak_argument_spec()

    mapper_spec = dict(
        id=dict(type='str'),
        name=dict(type='str'),
        identityProviderAlias=dict(type='str'),
        identityProviderMapper=dict(type='str'),
        config=dict(type='dict'),
    )

    meta_args = dict(
        state=dict(type='str',
                   default='present',
                   choices=['present', 'absent']),
        realm=dict(type='str', default='master'),
        alias=dict(type='str', required=True),
        add_read_token_role_on_create=dict(
            type='bool', aliases=['addReadTokenRoleOnCreate']),
        authenticate_by_default=dict(type='bool',
                                     aliases=['authenticateByDefault']),
        config=dict(type='dict'),
        display_name=dict(type='str', aliases=['displayName']),
        enabled=dict(type='bool'),
        first_broker_login_flow_alias=dict(
            type='str', aliases=['firstBrokerLoginFlowAlias']),
        link_only=dict(type='bool', aliases=['linkOnly']),
        post_broker_login_flow_alias=dict(type='str',
                                          aliases=['postBrokerLoginFlowAlias'
                                                   ]),
        provider_id=dict(type='str', aliases=['providerId']),
        store_token=dict(type='bool', aliases=['storeToken']),
        trust_email=dict(type='bool', aliases=['trustEmail']),
        mappers=dict(type='list', elements='dict', options=mapper_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')
    alias = module.params.get('alias')
    state = module.params.get('state')

    # Filter and map the parameters names that apply to the identity provider.
    idp_params = [
        x for x in module.params
        if x not in list(keycloak_argument_spec().keys()) +
        ['state', 'realm', 'mappers'] and module.params.get(x) is not None
    ]

    # See if it already exists in Keycloak
    before_idp = get_identity_provider_with_mappers(kc, alias, realm)

    # Build a proposed changeset from parameters given to this module
    changeset = {}

    for param in idp_params:
        new_param_value = module.params.get(param)
        old_value = before_idp[camel(param)] if camel(
            param) in before_idp else None
        if new_param_value != old_value:
            changeset[camel(param)] = new_param_value

    # special handling of mappers list to allow change detection
    if module.params.get('mappers') is not None:
        for change in module.params['mappers']:
            change = dict(
                (k, v) for k, v in change.items() if change[k] is not None)
            if change.get('id') is None and change.get('name') is None:
                module.fail_json(
                    msg=
                    'Either `name` or `id` has to be specified on each mapper.'
                )
            if before_idp == dict():
                old_mapper = dict()
            elif change.get('id') is not None:
                old_mapper = kc.get_identity_provider_mapper(
                    change['id'], alias, realm)
                if old_mapper is None:
                    old_mapper = dict()
            else:
                found = [
                    x for x in kc.get_identity_provider_mappers(alias, realm)
                    if x['name'] == change['name']
                ]
                if len(found) == 1:
                    old_mapper = found[0]
                else:
                    old_mapper = dict()
            new_mapper = old_mapper.copy()
            new_mapper.update(change)
            if new_mapper != old_mapper:
                if changeset.get('mappers') is None:
                    changeset['mappers'] = list()
                changeset['mappers'].append(new_mapper)

    # Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
    desired_idp = before_idp.copy()
    desired_idp.update(changeset)

    result['proposed'] = sanitize(changeset)
    result['existing'] = sanitize(before_idp)

    # Cater for when it doesn't exist (an empty dict)
    if not before_idp:
        if state == 'absent':
            # Do nothing and exit
            if module._diff:
                result['diff'] = dict(before='', after='')
            result['changed'] = False
            result['end_state'] = {}
            result['msg'] = 'Identity provider does not exist; doing nothing.'
            module.exit_json(**result)

        # Process a creation
        result['changed'] = True

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

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

        # create it
        desired_idp = desired_idp.copy()
        mappers = desired_idp.pop('mappers', [])
        kc.create_identity_provider(desired_idp, realm)
        for mapper in mappers:
            if mapper.get('identityProviderAlias') is None:
                mapper['identityProviderAlias'] = alias
            kc.create_identity_provider_mapper(mapper, alias, realm)
        after_idp = get_identity_provider_with_mappers(kc, alias, realm)

        result['end_state'] = sanitize(after_idp)

        result['msg'] = 'Identity provider {alias} has been created'.format(
            alias=alias)
        module.exit_json(**result)

    else:
        if state == 'present':
            # Process an update

            # no changes
            if desired_idp == before_idp:
                result['changed'] = False
                result['end_state'] = sanitize(desired_idp)
                result[
                    'msg'] = "No changes required to identity provider {alias}.".format(
                        alias=alias)
                module.exit_json(**result)

            # doing an update
            result['changed'] = True

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

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

            # do the update
            desired_idp = desired_idp.copy()
            updated_mappers = desired_idp.pop('mappers', [])
            kc.update_identity_provider(desired_idp, realm)
            for mapper in updated_mappers:
                if mapper.get('id') is not None:
                    kc.update_identity_provider_mapper(mapper, alias, realm)
                else:
                    if mapper.get('identityProviderAlias') is None:
                        mapper['identityProviderAlias'] = alias
                    kc.create_identity_provider_mapper(mapper, alias, realm)
            for mapper in [
                    x for x in before_idp['mappers']
                    if [y for y in updated_mappers
                        if y["name"] == x['name']] == []
            ]:
                kc.delete_identity_provider_mapper(mapper['id'], alias, realm)

            after_idp = get_identity_provider_with_mappers(kc, alias, realm)

            result['end_state'] = sanitize(after_idp)

            result[
                'msg'] = "Identity provider {alias} has been updated".format(
                    alias=alias)
            module.exit_json(**result)

        elif state == 'absent':
            # Process a deletion
            result['changed'] = True

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

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

            # delete it
            kc.delete_identity_provider(alias, realm)

            result['end_state'] = {}

            result[
                'msg'] = "Identity provider {alias} has been deleted".format(
                    alias=alias)

    module.exit_json(**result)