mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 12:50:22 -07:00
keycloak_userprofile: new module (#8651)
keycloak_userprofile: new keycloak module to manage user profiles (#8651)
This commit is contained in:
parent
d73f977b7a
commit
529af4984c
9 changed files with 2053 additions and 2 deletions
|
@ -10,8 +10,8 @@
|
|||
command: start-dev
|
||||
env:
|
||||
KC_HTTP_RELATIVE_PATH: /auth
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: password
|
||||
KEYCLOAK_ADMIN: "{{ admin_user }}"
|
||||
KEYCLOAK_ADMIN_PASSWORD: "{{ admin_password }}"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
detach: true
|
||||
|
|
5
tests/integration/targets/keycloak_userprofile/aliases
Normal file
5
tests/integration/targets/keycloak_userprofile/aliases
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
unsupported
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# dependencies:
|
||||
# - setup_docker
|
27
tests/integration/targets/keycloak_userprofile/readme.adoc
Normal file
27
tests/integration/targets/keycloak_userprofile/readme.adoc
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) Ansible Project
|
||||
// GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
To be able to run these integration tests a keycloak server must be
|
||||
reachable under a specific url with a specific admin user and password.
|
||||
The exact values expected for these parameters can be found in
|
||||
'vars/main.yml' file. A simple way to do this is to use the official
|
||||
keycloak docker images like this:
|
||||
|
||||
----
|
||||
docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=<url-path> -e KEYCLOAK_ADMIN=<admin_user> -e KEYCLOAK_ADMIN_PASSWORD=<admin_password> quay.io/keycloak/keycloak:24.0.5 start-dev
|
||||
----
|
||||
|
||||
Example with concrete values inserted:
|
||||
|
||||
----
|
||||
docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=/auth -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:24.0.5 start-dev
|
||||
----
|
||||
|
||||
This test suite can run against a fresh unconfigured server instance
|
||||
(no preconfiguration required) and cleans up after itself (undoes all
|
||||
its config changes) as long as it runs through completely. While its active
|
||||
it changes the server configuration in the following ways:
|
||||
|
||||
* creating, modifying and deleting some keycloak userprofiles
|
||||
|
301
tests/integration/targets/keycloak_userprofile/tasks/main.yml
Normal file
301
tests/integration/targets/keycloak_userprofile/tasks/main.yml
Normal file
|
@ -0,0 +1,301 @@
|
|||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
- name: Start container
|
||||
community.docker.docker_container:
|
||||
name: mykeycloak
|
||||
image: "quay.io/keycloak/keycloak:24.0.5"
|
||||
command: start-dev
|
||||
env:
|
||||
KC_HTTP_RELATIVE_PATH: /auth
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: password
|
||||
ports:
|
||||
- "8080:8080"
|
||||
detach: true
|
||||
auto_remove: true
|
||||
memory: 2200M
|
||||
|
||||
- name: Check default ports
|
||||
ansible.builtin.wait_for:
|
||||
host: "localhost"
|
||||
port: "8080"
|
||||
state: started # Port should be open
|
||||
delay: 30 # Wait before first check
|
||||
timeout: 50 # Stop checking after timeout (sec)
|
||||
|
||||
- name: Remove Keycloak test realm to avoid failures from previous failed runs
|
||||
community.general.keycloak_realm:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
id: "{{ realm }}"
|
||||
state: absent
|
||||
|
||||
- name: Create Keycloak test realm
|
||||
community.general.keycloak_realm:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
id: "{{ realm }}"
|
||||
state: present
|
||||
|
||||
- name: Create default User Profile (check mode)
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_default }}"
|
||||
check_mode: true
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile would be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg == "Userprofile declarative-user-profile would be created"
|
||||
|
||||
- name: Create default User Profile
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: present
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_default }}"
|
||||
diff: true
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile was created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg == "Userprofile declarative-user-profile created"
|
||||
|
||||
- name: Create default User Profile (test for idempotency)
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: present
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_default }}"
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile was in sync
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg == "Userprofile declarative-user-profile was in sync"
|
||||
|
||||
- name: Update default User Profile (check mode)
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: present
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_updated }}"
|
||||
check_mode: true
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile would be changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg.startswith("Userprofile declarative-user-profile would be changed:")
|
||||
|
||||
- name: Update default User Profile
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: present
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_updated }}"
|
||||
diff: true
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg.startswith("Userprofile declarative-user-profile changed:")
|
||||
|
||||
- name: Update default User Profile (test for idempotency)
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: present
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_updated }}"
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile was in sync
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg == "Userprofile declarative-user-profile was in sync"
|
||||
|
||||
## No force implemented
|
||||
# - name: Force update default User Profile
|
||||
# community.general.keycloak_userprofile:
|
||||
# auth_keycloak_url: "{{ url }}"
|
||||
# auth_realm: "{{ admin_realm }}"
|
||||
# auth_username: "{{ admin_user }}"
|
||||
# auth_password: "{{ admin_password }}"
|
||||
# force: true
|
||||
# state: present
|
||||
# parent_id: "{{ realm }}"
|
||||
# config: "{{ config_updated }}"
|
||||
# register: result
|
||||
#
|
||||
# - name: Assert that forced update ran correctly
|
||||
# assert:
|
||||
# that:
|
||||
# - result is changed
|
||||
# - result.end_state != {}
|
||||
# - result.end_state.providerId == "declarative-user-profile"
|
||||
# - result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
# - result.msg == "Userprofile declarative-user-profile was forcibly updated"
|
||||
|
||||
- name: Remove default User Profile
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: absent
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_default }}"
|
||||
diff: true
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile was deleted
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state == {}
|
||||
- result.msg == "Userprofile declarative-user-profile deleted"
|
||||
|
||||
- name: Remove default User Profile (test for idempotency)
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: absent
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_default }}"
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile not present
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.end_state == {}
|
||||
- result.msg == "Userprofile declarative-user-profile not present"
|
||||
|
||||
- name: Create User Profile with unmanaged attributes ENABLED
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: present
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_unmanaged_attributes_enabled }}"
|
||||
diff: true
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile was created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg == "Userprofile declarative-user-profile created"
|
||||
|
||||
- name: Attempt to change the User Profile to unmanaged ADMIN_EDIT
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: present
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_unmanaged_attributes_admin_edit }}"
|
||||
diff: true
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile was changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg.startswith("Userprofile declarative-user-profile changed:")
|
||||
|
||||
- name: Attempt to change the User Profile to unmanaged ADMIN_VIEW
|
||||
community.general.keycloak_userprofile:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
state: present
|
||||
parent_id: "{{ realm }}"
|
||||
config: "{{ config_unmanaged_attributes_admin_view }}"
|
||||
diff: true
|
||||
register: result
|
||||
|
||||
- name: Assert that User Profile was changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.end_state != {}
|
||||
- result.end_state.providerId == "declarative-user-profile"
|
||||
- result.end_state.providerType == "org.keycloak.userprofile.UserProfileProvider"
|
||||
- result.msg.startswith("Userprofile declarative-user-profile changed:")
|
||||
|
||||
- name: Remove Keycloak test realm
|
||||
community.general.keycloak_realm:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
id: "{{ realm }}"
|
||||
state: absent
|
111
tests/integration/targets/keycloak_userprofile/vars/main.yml
Normal file
111
tests/integration/targets/keycloak_userprofile/vars/main.yml
Normal file
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
url: http://localhost:8080/auth
|
||||
admin_realm: master
|
||||
admin_user: admin
|
||||
admin_password: password
|
||||
realm: realm_userprofile_test
|
||||
attributes_default:
|
||||
- name: username
|
||||
displayName: ${username}
|
||||
validations:
|
||||
length:
|
||||
min: 3
|
||||
max: 255
|
||||
usernameProhibitedCharacters: {}
|
||||
up_username_not_idn_homograph: {}
|
||||
annotations: {}
|
||||
permissions:
|
||||
view:
|
||||
- admin
|
||||
- user
|
||||
edit: []
|
||||
multivalued: false
|
||||
- name: email
|
||||
displayName: ${email}
|
||||
validations:
|
||||
email: {}
|
||||
length:
|
||||
max: 255
|
||||
annotations: {}
|
||||
required:
|
||||
roles:
|
||||
- user
|
||||
permissions:
|
||||
view:
|
||||
- admin
|
||||
- user
|
||||
edit: []
|
||||
multivalued: false
|
||||
- name: firstName
|
||||
displayName: ${firstName}
|
||||
validations:
|
||||
length:
|
||||
max: 255
|
||||
personNameProhibitedCharacters: {}
|
||||
annotations: {}
|
||||
required:
|
||||
roles:
|
||||
- user
|
||||
permissions:
|
||||
view:
|
||||
- admin
|
||||
- user
|
||||
edit: []
|
||||
multivalued: false
|
||||
- name: lastName
|
||||
displayName: ${lastName}
|
||||
validations:
|
||||
length:
|
||||
max: 255
|
||||
person_name_prohibited_characters: {}
|
||||
annotations: {}
|
||||
required:
|
||||
roles:
|
||||
- user
|
||||
permissions:
|
||||
view:
|
||||
- admin
|
||||
- user
|
||||
edit: []
|
||||
multivalued: false
|
||||
attributes_additional:
|
||||
- name: additionalAttribute
|
||||
displayName: additionalAttribute
|
||||
group: user-metadata
|
||||
required:
|
||||
roles:
|
||||
- user
|
||||
permissions:
|
||||
view:
|
||||
- admin
|
||||
- user
|
||||
edit: []
|
||||
multivalued: false
|
||||
groups_default:
|
||||
- name: user-metadata
|
||||
displayHeader: User metadata
|
||||
displayDescription: Attributes, which refer to user metadata
|
||||
config_default:
|
||||
kc_user_profile_config:
|
||||
- attributes: "{{ attributes_default }}"
|
||||
groups: "{{ groups_default }}"
|
||||
config_updated:
|
||||
kc_user_profile_config:
|
||||
- attributes: "{{ attributes_default + attributes_additional }}"
|
||||
groups: "{{ groups_default }}"
|
||||
config_unmanaged_attributes_enabled:
|
||||
kc_user_profile_config:
|
||||
- unmanagedAttributePolicy: ENABLED
|
||||
attributes: "{{ attributes_default }}"
|
||||
config_unmanaged_attributes_admin_edit:
|
||||
kc_user_profile_config:
|
||||
- unmanagedAttributePolicy: ADMIN_EDIT
|
||||
attributes: "{{ attributes_default }}"
|
||||
config_unmanaged_attributes_admin_view:
|
||||
kc_user_profile_config:
|
||||
- unmanagedAttributePolicy: ADMIN_VIEW
|
||||
attributes: "{{ attributes_default }}"
|
866
tests/unit/plugins/modules/test_keycloak_userprofile.py
Normal file
866
tests/unit/plugins/modules/test_keycloak_userprofile.py
Normal file
|
@ -0,0 +1,866 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2024, Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import patch
|
||||
from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, ModuleTestCase, set_module_args
|
||||
|
||||
from ansible_collections.community.general.plugins.modules import keycloak_userprofile
|
||||
|
||||
from itertools import count
|
||||
|
||||
from ansible.module_utils.six import StringIO
|
||||
|
||||
|
||||
@contextmanager
|
||||
def patch_keycloak_api(get_components=None, get_component=None, create_component=None, update_component=None, delete_component=None):
|
||||
"""Mock context manager for patching the methods in KeycloakAPI
|
||||
"""
|
||||
|
||||
obj = keycloak_userprofile.KeycloakAPI
|
||||
with patch.object(obj, 'get_components', side_effect=get_components) as mock_get_components:
|
||||
with patch.object(obj, 'get_component', side_effect=get_component) as mock_get_component:
|
||||
with patch.object(obj, 'create_component', side_effect=create_component) as mock_create_component:
|
||||
with patch.object(obj, 'update_component', side_effect=update_component) as mock_update_component:
|
||||
with patch.object(obj, 'delete_component', side_effect=delete_component) as mock_delete_component:
|
||||
yield mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component
|
||||
|
||||
|
||||
def get_response(object_with_future_response, method, get_id_call_count):
|
||||
if callable(object_with_future_response):
|
||||
return object_with_future_response()
|
||||
if isinstance(object_with_future_response, dict):
|
||||
return get_response(object_with_future_response[method], method, get_id_call_count)
|
||||
if isinstance(object_with_future_response, list):
|
||||
call_number = next(get_id_call_count)
|
||||
return get_response(object_with_future_response[call_number], method, get_id_call_count)
|
||||
return object_with_future_response
|
||||
|
||||
|
||||
def build_mocked_request(get_id_user_count, response_dict):
|
||||
def _mocked_requests(*args, **kwargs):
|
||||
url = args[0]
|
||||
method = kwargs['method']
|
||||
future_response = response_dict.get(url, None)
|
||||
return get_response(future_response, method, get_id_user_count)
|
||||
return _mocked_requests
|
||||
|
||||
|
||||
def create_wrapper(text_as_string):
|
||||
"""Allow to mock many times a call to one address.
|
||||
Without this function, the StringIO is empty for the second call.
|
||||
"""
|
||||
def _create_wrapper():
|
||||
return StringIO(text_as_string)
|
||||
return _create_wrapper
|
||||
|
||||
|
||||
def mock_good_connection():
|
||||
token_response = {
|
||||
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token': create_wrapper('{"access_token": "alongtoken"}'),
|
||||
}
|
||||
return patch(
|
||||
'ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url',
|
||||
side_effect=build_mocked_request(count(), token_response),
|
||||
autospec=True
|
||||
)
|
||||
|
||||
|
||||
class TestKeycloakUserprofile(ModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestKeycloakUserprofile, self).setUp()
|
||||
self.module = keycloak_userprofile
|
||||
|
||||
def test_create_when_absent(self):
|
||||
"""Add a new userprofile"""
|
||||
|
||||
module_args = {
|
||||
"auth_keycloak_url": "http://keycloak.url/auth",
|
||||
"auth_realm": "master",
|
||||
"auth_username": "admin",
|
||||
"auth_password": "admin",
|
||||
"parent_id": "realm-name",
|
||||
"state": "present",
|
||||
"provider_id": "declarative-user-profile",
|
||||
"config": {
|
||||
"kc_user_profile_config": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"annotations": {},
|
||||
"displayName": "${username}",
|
||||
"multivalued": False,
|
||||
"name": "username",
|
||||
"permissions": {
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"required": None,
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255,
|
||||
"min": 3
|
||||
},
|
||||
"up_username_not_idn_homograph": {},
|
||||
"username_prohibited_characters": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"annotations": {},
|
||||
"displayName": "${email}",
|
||||
"multivalued": False,
|
||||
"name": "email",
|
||||
"permissions": {
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"validations": {
|
||||
"email": {},
|
||||
"length": {
|
||||
"max": 255
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"annotations": {},
|
||||
"displayName": "${firstName}",
|
||||
"multivalued": False,
|
||||
"name": "firstName",
|
||||
"permissions": {
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person_name_prohibited_characters": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"annotations": {},
|
||||
"displayName": "${lastName}",
|
||||
"multivalued": False,
|
||||
"name": "lastName",
|
||||
"permissions": {
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person_name_prohibited_characters": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"displayDescription": "Attributes, which refer to user metadata",
|
||||
"displayHeader": "User metadata",
|
||||
"name": "user-metadata"
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
return_value_component_create = [
|
||||
{
|
||||
"id": "4ba43451-6bb4-4b50-969f-e890539f15e3",
|
||||
"parentId": "realm-name",
|
||||
"providerId": "declarative-user-profile",
|
||||
"providerType": "org.keycloak.userprofile.UserProfileProvider",
|
||||
"config": {
|
||||
"kc.user.profile.config": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"name": "username",
|
||||
"displayName": "${username}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"min": 3,
|
||||
"max": 255
|
||||
},
|
||||
"username-prohibited-characters": {},
|
||||
"up-username-not-idn-homograph": {}
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {},
|
||||
"required": None
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"displayName": "${email}",
|
||||
"validations": {
|
||||
"email": {},
|
||||
"length": {
|
||||
"max": 255
|
||||
}
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
},
|
||||
{
|
||||
"name": "firstName",
|
||||
"displayName": "${firstName}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person-name-prohibited-characters": {}
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
},
|
||||
{
|
||||
"name": "lastName",
|
||||
"displayName": "${lastName}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person-name-prohibited-characters": {}
|
||||
},
|
||||
"required": {
|
||||
|
||||
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "user-metadata",
|
||||
"displayHeader": "User metadata",
|
||||
"displayDescription": "Attributes, which refer to user metadata",
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
return_value_get_components_get = [
|
||||
[], []
|
||||
]
|
||||
changed = True
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_components=return_value_get_components_get, create_component=return_value_component_create) as (
|
||||
mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 1)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
def test_create_when_present(self):
|
||||
"""Update existing userprofile"""
|
||||
|
||||
module_args = {
|
||||
"auth_keycloak_url": "http://keycloak.url/auth",
|
||||
"auth_realm": "master",
|
||||
"auth_username": "admin",
|
||||
"auth_password": "admin",
|
||||
"parent_id": "realm-name",
|
||||
"state": "present",
|
||||
"provider_id": "declarative-user-profile",
|
||||
"config": {
|
||||
"kc_user_profile_config": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"annotations": {},
|
||||
"displayName": "${username}",
|
||||
"multivalued": False,
|
||||
"name": "username",
|
||||
"permissions": {
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"required": None,
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255,
|
||||
"min": 3
|
||||
},
|
||||
"up_username_not_idn_homograph": {},
|
||||
"username_prohibited_characters": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"annotations": {},
|
||||
"displayName": "${email}",
|
||||
"multivalued": False,
|
||||
"name": "email",
|
||||
"permissions": {
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"validations": {
|
||||
"email": {},
|
||||
"length": {
|
||||
"max": 255
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"annotations": {},
|
||||
"displayName": "${firstName}",
|
||||
"multivalued": False,
|
||||
"name": "firstName",
|
||||
"permissions": {
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person_name_prohibited_characters": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"annotations": {},
|
||||
"displayName": "${lastName}",
|
||||
"multivalued": False,
|
||||
"name": "lastName",
|
||||
"permissions": {
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person_name_prohibited_characters": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"displayDescription": "Attributes, which refer to user metadata",
|
||||
"displayHeader": "User metadata",
|
||||
"name": "user-metadata"
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
return_value_get_components_get = [
|
||||
[
|
||||
{
|
||||
"id": "4ba43451-6bb4-4b50-969f-e890539f15e3",
|
||||
"parentId": "realm-1",
|
||||
"providerId": "declarative-user-profile",
|
||||
"providerType": "org.keycloak.userprofile.UserProfileProvider",
|
||||
"config": {
|
||||
"kc.user.profile.config": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"name": "username",
|
||||
"displayName": "${username}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"min": 3,
|
||||
"max": 255
|
||||
},
|
||||
"username-prohibited-characters": {},
|
||||
"up-username-not-idn-homograph": {}
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {},
|
||||
"required": None
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"displayName": "${email}",
|
||||
"validations": {
|
||||
"email": {},
|
||||
"length": {
|
||||
"max": 255
|
||||
}
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
},
|
||||
{
|
||||
"name": "firstName",
|
||||
"displayName": "${firstName}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person-name-prohibited-characters": {}
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
},
|
||||
{
|
||||
"name": "lastName",
|
||||
"displayName": "${lastName}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person-name-prohibited-characters": {}
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "user-metadata",
|
||||
"displayHeader": "User metadata",
|
||||
"displayDescription": "Attributes, which refer to user metadata",
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
[]
|
||||
]
|
||||
return_value_component_update = [
|
||||
None
|
||||
]
|
||||
changed = True
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_components=return_value_get_components_get,
|
||||
update_component=return_value_component_update) as (
|
||||
mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 1)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
def test_delete_when_absent(self):
|
||||
"""Remove an absent userprofile"""
|
||||
|
||||
module_args = {
|
||||
'auth_keycloak_url': 'http://keycloak.url/auth',
|
||||
'auth_realm': 'master',
|
||||
'auth_username': 'admin',
|
||||
'auth_password': 'admin',
|
||||
'parent_id': 'realm-name',
|
||||
'provider_id': 'declarative-user-profile',
|
||||
'state': 'absent',
|
||||
}
|
||||
return_value_get_components_get = [
|
||||
[]
|
||||
]
|
||||
changed = False
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_components=return_value_get_components_get) as (
|
||||
mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
def test_delete_when_present(self):
|
||||
"""Remove an existing userprofile"""
|
||||
|
||||
module_args = {
|
||||
'auth_keycloak_url': 'http://keycloak.url/auth',
|
||||
'auth_realm': 'master',
|
||||
'auth_username': 'admin',
|
||||
'auth_password': 'admin',
|
||||
'parent_id': 'realm-name',
|
||||
'provider_id': 'declarative-user-profile',
|
||||
'state': 'absent',
|
||||
}
|
||||
return_value_get_components_get = [
|
||||
[
|
||||
{
|
||||
"id": "4ba43451-6bb4-4b50-969f-e890539f15e3",
|
||||
"parentId": "realm-1",
|
||||
"providerId": "declarative-user-profile",
|
||||
"providerType": "org.keycloak.userprofile.UserProfileProvider",
|
||||
"config": {
|
||||
"kc.user.profile.config": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"name": "username",
|
||||
"displayName": "${username}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"min": 3,
|
||||
"max": 255
|
||||
},
|
||||
"username-prohibited-characters": {},
|
||||
"up-username-not-idn-homograph": {}
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {},
|
||||
"required": None
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"displayName": "${email}",
|
||||
"validations": {
|
||||
"email": {},
|
||||
"length": {
|
||||
"max": 255
|
||||
}
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
},
|
||||
{
|
||||
"name": "firstName",
|
||||
"displayName": "${firstName}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person-name-prohibited-characters": {}
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
},
|
||||
{
|
||||
"name": "lastName",
|
||||
"displayName": "${lastName}",
|
||||
"validations": {
|
||||
"length": {
|
||||
"max": 255
|
||||
},
|
||||
"person-name-prohibited-characters": {}
|
||||
},
|
||||
"required": {
|
||||
"roles": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"view": [
|
||||
"admin",
|
||||
"user"
|
||||
],
|
||||
"edit": [
|
||||
"admin",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"multivalued": False,
|
||||
"annotations": {}
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "user-metadata",
|
||||
"displayHeader": "User metadata",
|
||||
"displayDescription": "Attributes, which refer to user metadata",
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
[]
|
||||
]
|
||||
return_value_component_delete = [
|
||||
None
|
||||
]
|
||||
changed = True
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_components=return_value_get_components_get, delete_component=return_value_component_delete) as (
|
||||
mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 1)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Add table
Add a link
Reference in a new issue