mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-05-25 10:29:09 -07:00
Keycloak: add realm management (#2155)
* Keycloak: add realm management * Minor fixes * Review fixes * Remove sort of list because condition on list cannot be true * Add exception in fail_json and update test * Change output for secret and version in comments * Update copyright Co-authored-by: Felix Fontein <felix@fontein.de> * Add missing traceback * Apply suggestions from code review * Update plugins/modules/identity/keycloak/keycloak_realm.py Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
fe2757f057
commit
cecbc2be2d
5 changed files with 1171 additions and 0 deletions
787
plugins/modules/identity/keycloak/keycloak_realm.py
Normal file
787
plugins/modules/identity/keycloak/keycloak_realm.py
Normal file
|
@ -0,0 +1,787 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2017, Eike Frost <ei@kefro.st>
|
||||
# Copyright (c) 2021, Christophe Gilles <christophe.gilles54@gmail.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: keycloak_realm
|
||||
|
||||
short_description: Allows administration of Keycloak realm via Keycloak API
|
||||
version_added: 3.0.0
|
||||
|
||||
|
||||
description:
|
||||
- This module allows the administration of Keycloak realm via the Keycloak REST API. It
|
||||
requires access to the REST API via OpenID Connect; the user connecting and the realm being
|
||||
used must have the requisite access rights. In a default Keycloak installation, admin-cli
|
||||
and an admin user would work, as would a separate realm definition with the scope tailored
|
||||
to your needs and a user having the expected roles.
|
||||
|
||||
- The names of module options are snake_cased versions of the camelCase ones found in the
|
||||
Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/8.0/rest-api/index.html).
|
||||
Aliases are provided so camelCased versions can be used as well.
|
||||
|
||||
- The Keycloak API does not always sanity check inputs e.g. you can set
|
||||
SAML-specific settings on an OpenID Connect client for instance and vice versa. Be careful.
|
||||
If you do not specify a setting, usually a sensible default is chosen.
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- State of the realm.
|
||||
- On C(present), the realm will be created (or updated if it exists already).
|
||||
- On C(absent), the realm will be removed if it exists.
|
||||
choices: ['present', 'absent']
|
||||
default: 'present'
|
||||
type: str
|
||||
|
||||
id:
|
||||
description:
|
||||
- The realm to create.
|
||||
type: str
|
||||
realm:
|
||||
description:
|
||||
- The realm name.
|
||||
type: str
|
||||
access_code_lifespan:
|
||||
description:
|
||||
- The realm access code lifespan.
|
||||
aliases:
|
||||
- accessCodeLifespan
|
||||
type: int
|
||||
access_code_lifespan_login:
|
||||
description:
|
||||
- The realm access code lifespan login.
|
||||
aliases:
|
||||
- accessCodeLifespanLogin
|
||||
type: int
|
||||
access_code_lifespan_user_action:
|
||||
description:
|
||||
- The realm access code lifespan user action.
|
||||
aliases:
|
||||
- accessCodeLifespanUserAction
|
||||
type: int
|
||||
access_token_lifespan:
|
||||
description:
|
||||
- The realm access token lifespan.
|
||||
aliases:
|
||||
- accessTokenLifespan
|
||||
type: int
|
||||
access_token_lifespan_for_implicit_flow:
|
||||
description:
|
||||
- The realm access token lifespan for implicit flow.
|
||||
aliases:
|
||||
- accessTokenLifespanForImplicitFlow
|
||||
type: int
|
||||
account_theme:
|
||||
description:
|
||||
- The realm account theme.
|
||||
aliases:
|
||||
- accountTheme
|
||||
type: str
|
||||
action_token_generated_by_admin_lifespan:
|
||||
description:
|
||||
- The realm action token generated by admin lifespan.
|
||||
aliases:
|
||||
- actionTokenGeneratedByAdminLifespan
|
||||
type: int
|
||||
action_token_generated_by_user_lifespan:
|
||||
description:
|
||||
- The realm action token generated by user lifespan.
|
||||
aliases:
|
||||
- actionTokenGeneratedByUserLifespan
|
||||
type: int
|
||||
admin_events_details_enabled:
|
||||
description:
|
||||
- The realm admin events details enabled.
|
||||
aliases:
|
||||
- adminEventsDetailsEnabled
|
||||
type: bool
|
||||
admin_events_enabled:
|
||||
description:
|
||||
- The realm admin events enabled.
|
||||
aliases:
|
||||
- adminEventsEnabled
|
||||
type: bool
|
||||
admin_theme:
|
||||
description:
|
||||
- The realm admin theme.
|
||||
aliases:
|
||||
- adminTheme
|
||||
type: str
|
||||
attributes:
|
||||
description:
|
||||
- The realm attributes.
|
||||
type: dict
|
||||
browser_flow:
|
||||
description:
|
||||
- The realm browser flow.
|
||||
aliases:
|
||||
- browserFlow
|
||||
type: str
|
||||
browser_security_headers:
|
||||
description:
|
||||
- The realm browser security headers.
|
||||
aliases:
|
||||
- browserSecurityHeaders
|
||||
type: dict
|
||||
brute_force_protected:
|
||||
description:
|
||||
- The realm brute force protected.
|
||||
aliases:
|
||||
- bruteForceProtected
|
||||
type: bool
|
||||
client_authentication_flow:
|
||||
description:
|
||||
- The realm client authentication flow.
|
||||
aliases:
|
||||
- clientAuthenticationFlow
|
||||
type: str
|
||||
client_scope_mappings:
|
||||
description:
|
||||
- The realm client scope mappings.
|
||||
aliases:
|
||||
- clientScopeMappings
|
||||
type: dict
|
||||
default_default_client_scopes:
|
||||
description:
|
||||
- The realm default default client scopes.
|
||||
aliases:
|
||||
- defaultDefaultClientScopes
|
||||
type: list
|
||||
elements: dict
|
||||
default_groups:
|
||||
description:
|
||||
- The realm default groups.
|
||||
aliases:
|
||||
- defaultGroups
|
||||
type: list
|
||||
elements: dict
|
||||
default_locale:
|
||||
description:
|
||||
- The realm default locale.
|
||||
aliases:
|
||||
- defaultLocale
|
||||
type: str
|
||||
default_optional_client_scopes:
|
||||
description:
|
||||
- The realm default optional client scopes.
|
||||
aliases:
|
||||
- defaultOptionalClientScopes
|
||||
type: list
|
||||
elements: dict
|
||||
default_roles:
|
||||
description:
|
||||
- The realm default roles.
|
||||
aliases:
|
||||
- defaultRoles
|
||||
type: list
|
||||
elements: dict
|
||||
default_signature_algorithm:
|
||||
description:
|
||||
- The realm default signature algorithm.
|
||||
aliases:
|
||||
- defaultSignatureAlgorithm
|
||||
type: str
|
||||
direct_grant_flow:
|
||||
description:
|
||||
- The realm direct grant flow.
|
||||
aliases:
|
||||
- directGrantFlow
|
||||
type: str
|
||||
display_name:
|
||||
description:
|
||||
- The realm display name.
|
||||
aliases:
|
||||
- displayName
|
||||
type: str
|
||||
display_name_html:
|
||||
description:
|
||||
- The realm display name HTML.
|
||||
aliases:
|
||||
- displayNameHtml
|
||||
type: str
|
||||
docker_authentication_flow:
|
||||
description:
|
||||
- The realm docker authentication flow.
|
||||
aliases:
|
||||
- dockerAuthenticationFlow
|
||||
type: str
|
||||
duplicate_emails_allowed:
|
||||
description:
|
||||
- The realm duplicate emails allowed option.
|
||||
aliases:
|
||||
- duplicateEmailsAllowed
|
||||
type: bool
|
||||
edit_username_allowed:
|
||||
description:
|
||||
- The realm edit username allowed option.
|
||||
aliases:
|
||||
- editUsernameAllowed
|
||||
type: bool
|
||||
email_theme:
|
||||
description:
|
||||
- The realm email theme.
|
||||
aliases:
|
||||
- emailTheme
|
||||
type: str
|
||||
enabled:
|
||||
description:
|
||||
- The realm enabled option.
|
||||
type: bool
|
||||
enabled_event_types:
|
||||
description:
|
||||
- The realm enabled event types.
|
||||
aliases:
|
||||
- enabledEventTypes
|
||||
type: list
|
||||
elements: str
|
||||
events_expiration:
|
||||
description:
|
||||
- The realm events expiration.
|
||||
aliases:
|
||||
- eventsExpiration
|
||||
type: int
|
||||
events_listeners:
|
||||
description:
|
||||
- The realm events listeners.
|
||||
aliases:
|
||||
- eventsListeners
|
||||
type: list
|
||||
elements: dict
|
||||
failure_factor:
|
||||
description:
|
||||
- The realm failure factor.
|
||||
aliases:
|
||||
- failureFactor
|
||||
type: int
|
||||
internationalization_enabled:
|
||||
description:
|
||||
- The realm internationalization enabled option.
|
||||
aliases:
|
||||
- internationalizationEnabled
|
||||
type: bool
|
||||
login_theme:
|
||||
description:
|
||||
- The realm login theme.
|
||||
aliases:
|
||||
- loginTheme
|
||||
type: str
|
||||
login_with_email_allowed:
|
||||
description:
|
||||
- The realm login with email allowed option.
|
||||
aliases:
|
||||
- loginWithEmailAllowed
|
||||
type: bool
|
||||
max_delta_time_seconds:
|
||||
description:
|
||||
- The realm max delta time in seconds.
|
||||
aliases:
|
||||
- maxDeltaTimeSeconds
|
||||
type: int
|
||||
max_failure_wait_seconds:
|
||||
description:
|
||||
- The realm max failure wait in seconds.
|
||||
aliases:
|
||||
- maxFailureWaitSeconds
|
||||
type: int
|
||||
minimum_quick_login_wait_seconds:
|
||||
description:
|
||||
- The realm minimum quick login wait in seconds.
|
||||
aliases:
|
||||
- minimumQuickLoginWaitSeconds
|
||||
type: int
|
||||
not_before:
|
||||
description:
|
||||
- The realm not before.
|
||||
aliases:
|
||||
- notBefore
|
||||
type: int
|
||||
offline_session_idle_timeout:
|
||||
description:
|
||||
- The realm offline session idle timeout.
|
||||
aliases:
|
||||
- offlineSessionIdleTimeout
|
||||
type: int
|
||||
offline_session_max_lifespan:
|
||||
description:
|
||||
- The realm offline session max lifespan.
|
||||
aliases:
|
||||
- offlineSessionMaxLifespan
|
||||
type: int
|
||||
offline_session_max_lifespan_enabled:
|
||||
description:
|
||||
- The realm offline session max lifespan enabled option.
|
||||
aliases:
|
||||
- offlineSessionMaxLifespanEnabled
|
||||
type: bool
|
||||
otp_policy_algorithm:
|
||||
description:
|
||||
- The realm otp policy algorithm.
|
||||
aliases:
|
||||
- otpPolicyAlgorithm
|
||||
type: str
|
||||
otp_policy_digits:
|
||||
description:
|
||||
- The realm otp policy digits.
|
||||
aliases:
|
||||
- otpPolicyDigits
|
||||
type: int
|
||||
otp_policy_initial_counter:
|
||||
description:
|
||||
- The realm otp policy initial counter.
|
||||
aliases:
|
||||
- otpPolicyInitialCounter
|
||||
type: int
|
||||
otp_policy_look_ahead_window:
|
||||
description:
|
||||
- The realm otp policy look ahead window.
|
||||
aliases:
|
||||
- otpPolicyLookAheadWindow
|
||||
type: int
|
||||
otp_policy_period:
|
||||
description:
|
||||
- The realm otp policy period.
|
||||
aliases:
|
||||
- otpPolicyPeriod
|
||||
type: int
|
||||
otp_policy_type:
|
||||
description:
|
||||
- The realm otp policy type.
|
||||
aliases:
|
||||
- otpPolicyType
|
||||
type: str
|
||||
otp_supported_applications:
|
||||
description:
|
||||
- The realm otp supported applications.
|
||||
aliases:
|
||||
- otpSupportedApplications
|
||||
type: list
|
||||
elements: str
|
||||
password_policy:
|
||||
description:
|
||||
- The realm password policy.
|
||||
aliases:
|
||||
- passwordPolicy
|
||||
type: str
|
||||
permanent_lockout:
|
||||
description:
|
||||
- The realm permanent lockout.
|
||||
aliases:
|
||||
- permanentLockout
|
||||
type: bool
|
||||
quick_login_check_milli_seconds:
|
||||
description:
|
||||
- The realm quick login check in milliseconds.
|
||||
aliases:
|
||||
- quickLoginCheckMilliSeconds
|
||||
type: int
|
||||
refresh_token_max_reuse:
|
||||
description:
|
||||
- The realm refresh token max reuse.
|
||||
aliases:
|
||||
- refreshTokenMaxReuse
|
||||
type: int
|
||||
registration_allowed:
|
||||
description:
|
||||
- The realm registration allowed option.
|
||||
aliases:
|
||||
- registrationAllowed
|
||||
type: bool
|
||||
registration_email_as_username:
|
||||
description:
|
||||
- The realm registration email as username option.
|
||||
aliases:
|
||||
- registrationEmailAsUsername
|
||||
type: bool
|
||||
registration_flow:
|
||||
description:
|
||||
- The realm registration flow.
|
||||
aliases:
|
||||
- registrationFlow
|
||||
type: str
|
||||
remember_me:
|
||||
description:
|
||||
- The realm remember me option.
|
||||
aliases:
|
||||
- rememberMe
|
||||
type: bool
|
||||
reset_credentials_flow:
|
||||
description:
|
||||
- The realm reset credentials flow.
|
||||
aliases:
|
||||
- resetCredentialsFlow
|
||||
type: str
|
||||
reset_password_allowed:
|
||||
description:
|
||||
- The realm reset password allowed option.
|
||||
aliases:
|
||||
- resetPasswordAllowed
|
||||
type: bool
|
||||
revoke_refresh_token:
|
||||
description:
|
||||
- The realm revoke refresh token option.
|
||||
aliases:
|
||||
- revokeRefreshToken
|
||||
type: bool
|
||||
smtp_server:
|
||||
description:
|
||||
- The realm smtp server.
|
||||
aliases:
|
||||
- smtpServer
|
||||
type: dict
|
||||
ssl_required:
|
||||
description:
|
||||
- The realm ssl required option.
|
||||
aliases:
|
||||
- sslRequired
|
||||
type: bool
|
||||
sso_session_idle_timeout:
|
||||
description:
|
||||
- The realm sso session idle timeout.
|
||||
aliases:
|
||||
- ssoSessionIdleTimeout
|
||||
type: int
|
||||
sso_session_idle_timeout_remember_me:
|
||||
description:
|
||||
- The realm sso session idle timeout remember me.
|
||||
aliases:
|
||||
- ssoSessionIdleTimeoutRememberMe
|
||||
type: int
|
||||
sso_session_max_lifespan:
|
||||
description:
|
||||
- The realm sso session max lifespan.
|
||||
aliases:
|
||||
- ssoSessionMaxLifespan
|
||||
type: int
|
||||
sso_session_max_lifespan_remember_me:
|
||||
description:
|
||||
- The realm sso session max lifespan remember me.
|
||||
aliases:
|
||||
- ssoSessionMaxLifespanRememberMe
|
||||
type: int
|
||||
supported_locales:
|
||||
description:
|
||||
- The realm supported locales.
|
||||
aliases:
|
||||
- supportedLocales
|
||||
type: list
|
||||
elements: str
|
||||
user_managed_access_allowed:
|
||||
description:
|
||||
- The realm user managed access allowed option.
|
||||
aliases:
|
||||
- userManagedAccessAllowed
|
||||
type: bool
|
||||
verify_email:
|
||||
description:
|
||||
- The realm verify email option.
|
||||
aliases:
|
||||
- verifyEmail
|
||||
type: bool
|
||||
wait_increment_seconds:
|
||||
description:
|
||||
- The realm wait increment in seconds.
|
||||
aliases:
|
||||
- waitIncrementSeconds
|
||||
type: int
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.general.keycloak
|
||||
|
||||
|
||||
author:
|
||||
- Christophe Gilles (@kris2kris)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create or update Keycloak realm (minimal example)
|
||||
community.general.keycloak_realm:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: USERNAME
|
||||
auth_password: PASSWORD
|
||||
id: realm
|
||||
state: present
|
||||
|
||||
- name: Delete a Keycloak realm
|
||||
community.general.keycloak_realm:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: USERNAME
|
||||
auth_password: PASSWORD
|
||||
id: test
|
||||
state: absent
|
||||
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Realm testrealm has been updated"
|
||||
|
||||
proposed:
|
||||
description: realm representation of proposed changes to realm
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
id: "test"
|
||||
}
|
||||
existing:
|
||||
description: realm representation of existing realm (sample is truncated)
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
"attributes": {
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
end_state:
|
||||
description: realm representation of realm after module execution (sample is truncated)
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
"attributes": {
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
|
||||
keycloak_argument_spec, get_token, KeycloakError
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def sanitize_cr(realmrep):
|
||||
""" Removes probably sensitive details from a realm representation
|
||||
|
||||
:param realmrep: the realmrep dict to be sanitized
|
||||
:return: sanitized realmrep dict
|
||||
"""
|
||||
result = realmrep.copy()
|
||||
if 'secret' in result:
|
||||
result['secret'] = '********'
|
||||
if 'attributes' in result:
|
||||
if 'saml.signing.private.key' in result['attributes']:
|
||||
result['attributes'] = result['attributes'].copy()
|
||||
result['attributes']['saml.signing.private.key'] = '********'
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Module execution
|
||||
|
||||
:return:
|
||||
"""
|
||||
argument_spec = keycloak_argument_spec()
|
||||
|
||||
meta_args = dict(
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
|
||||
id=dict(type='str'),
|
||||
realm=dict(type='str'),
|
||||
access_code_lifespan=dict(type='int', aliases=['accessCodeLifespan']),
|
||||
access_code_lifespan_login=dict(type='int', aliases=['accessCodeLifespanLogin']),
|
||||
access_code_lifespan_user_action=dict(type='int', aliases=['accessCodeLifespanUserAction']),
|
||||
access_token_lifespan=dict(type='int', aliases=['accessTokenLifespan'], no_log=False),
|
||||
access_token_lifespan_for_implicit_flow=dict(type='int', aliases=['accessTokenLifespanForImplicitFlow'], no_log=False),
|
||||
account_theme=dict(type='str', aliases=['accountTheme']),
|
||||
action_token_generated_by_admin_lifespan=dict(type='int', aliases=['actionTokenGeneratedByAdminLifespan'], no_log=False),
|
||||
action_token_generated_by_user_lifespan=dict(type='int', aliases=['actionTokenGeneratedByUserLifespan'], no_log=False),
|
||||
admin_events_details_enabled=dict(type='bool', aliases=['adminEventsDetailsEnabled']),
|
||||
admin_events_enabled=dict(type='bool', aliases=['adminEventsEnabled']),
|
||||
admin_theme=dict(type='str', aliases=['adminTheme']),
|
||||
attributes=dict(type='dict'),
|
||||
browser_flow=dict(type='str', aliases=['browserFlow']),
|
||||
browser_security_headers=dict(type='dict', aliases=['browserSecurityHeaders']),
|
||||
brute_force_protected=dict(type='bool', aliases=['bruteForceProtected']),
|
||||
client_authentication_flow=dict(type='str', aliases=['clientAuthenticationFlow']),
|
||||
client_scope_mappings=dict(type='dict', aliases=['clientScopeMappings']),
|
||||
default_default_client_scopes=dict(type='list', elements='dict', aliases=['defaultDefaultClientScopes']),
|
||||
default_groups=dict(type='list', elements='dict', aliases=['defaultGroups']),
|
||||
default_locale=dict(type='str', aliases=['defaultLocale']),
|
||||
default_optional_client_scopes=dict(type='list', elements='dict', aliases=['defaultOptionalClientScopes']),
|
||||
default_roles=dict(type='list', elements='dict', aliases=['defaultRoles']),
|
||||
default_signature_algorithm=dict(type='str', aliases=['defaultSignatureAlgorithm']),
|
||||
direct_grant_flow=dict(type='str', aliases=['directGrantFlow']),
|
||||
display_name=dict(type='str', aliases=['displayName']),
|
||||
display_name_html=dict(type='str', aliases=['displayNameHtml']),
|
||||
docker_authentication_flow=dict(type='str', aliases=['dockerAuthenticationFlow']),
|
||||
duplicate_emails_allowed=dict(type='bool', aliases=['duplicateEmailsAllowed']),
|
||||
edit_username_allowed=dict(type='bool', aliases=['editUsernameAllowed']),
|
||||
email_theme=dict(type='str', aliases=['emailTheme']),
|
||||
enabled=dict(type='bool'),
|
||||
enabled_event_types=dict(type='list', elements='str', aliases=['enabledEventTypes']),
|
||||
events_expiration=dict(type='int', aliases=['eventsExpiration']),
|
||||
events_listeners=dict(type='list', elements='dict', aliases=['eventsListeners']),
|
||||
failure_factor=dict(type='int', aliases=['failureFactor']),
|
||||
internationalization_enabled=dict(type='bool', aliases=['internationalizationEnabled']),
|
||||
login_theme=dict(type='str', aliases=['loginTheme']),
|
||||
login_with_email_allowed=dict(type='bool', aliases=['loginWithEmailAllowed']),
|
||||
max_delta_time_seconds=dict(type='int', aliases=['maxDeltaTimeSeconds']),
|
||||
max_failure_wait_seconds=dict(type='int', aliases=['maxFailureWaitSeconds']),
|
||||
minimum_quick_login_wait_seconds=dict(type='int', aliases=['minimumQuickLoginWaitSeconds']),
|
||||
not_before=dict(type='int', aliases=['notBefore']),
|
||||
offline_session_idle_timeout=dict(type='int', aliases=['offlineSessionIdleTimeout']),
|
||||
offline_session_max_lifespan=dict(type='int', aliases=['offlineSessionMaxLifespan']),
|
||||
offline_session_max_lifespan_enabled=dict(type='bool', aliases=['offlineSessionMaxLifespanEnabled']),
|
||||
otp_policy_algorithm=dict(type='str', aliases=['otpPolicyAlgorithm']),
|
||||
otp_policy_digits=dict(type='int', aliases=['otpPolicyDigits']),
|
||||
otp_policy_initial_counter=dict(type='int', aliases=['otpPolicyInitialCounter']),
|
||||
otp_policy_look_ahead_window=dict(type='int', aliases=['otpPolicyLookAheadWindow']),
|
||||
otp_policy_period=dict(type='int', aliases=['otpPolicyPeriod']),
|
||||
otp_policy_type=dict(type='str', aliases=['otpPolicyType']),
|
||||
otp_supported_applications=dict(type='list', elements='str', aliases=['otpSupportedApplications']),
|
||||
password_policy=dict(type='str', aliases=['passwordPolicy'], no_log=False),
|
||||
permanent_lockout=dict(type='bool', aliases=['permanentLockout']),
|
||||
quick_login_check_milli_seconds=dict(type='int', aliases=['quickLoginCheckMilliSeconds']),
|
||||
refresh_token_max_reuse=dict(type='int', aliases=['refreshTokenMaxReuse'], no_log=False),
|
||||
registration_allowed=dict(type='bool', aliases=['registrationAllowed']),
|
||||
registration_email_as_username=dict(type='bool', aliases=['registrationEmailAsUsername']),
|
||||
registration_flow=dict(type='str', aliases=['registrationFlow']),
|
||||
remember_me=dict(type='bool', aliases=['rememberMe']),
|
||||
reset_credentials_flow=dict(type='str', aliases=['resetCredentialsFlow']),
|
||||
reset_password_allowed=dict(type='bool', aliases=['resetPasswordAllowed']),
|
||||
revoke_refresh_token=dict(type='bool', aliases=['revokeRefreshToken']),
|
||||
smtp_server=dict(type='dict', aliases=['smtpServer']),
|
||||
ssl_required=dict(type='bool', aliases=['sslRequired']),
|
||||
sso_session_idle_timeout=dict(type='int', aliases=['ssoSessionIdleTimeout']),
|
||||
sso_session_idle_timeout_remember_me=dict(type='int', aliases=['ssoSessionIdleTimeoutRememberMe']),
|
||||
sso_session_max_lifespan=dict(type='int', aliases=['ssoSessionMaxLifespan']),
|
||||
sso_session_max_lifespan_remember_me=dict(type='int', aliases=['ssoSessionMaxLifespanRememberMe']),
|
||||
supported_locales=dict(type='list', elements='str', aliases=['supportedLocales']),
|
||||
user_managed_access_allowed=dict(type='bool', aliases=['userManagedAccessAllowed']),
|
||||
verify_email=dict(type='bool', aliases=['verifyEmail']),
|
||||
wait_increment_seconds=dict(type='int', aliases=['waitIncrementSeconds']),
|
||||
)
|
||||
argument_spec.update(meta_args)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=([['id', 'realm', 'enabled'],
|
||||
['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')
|
||||
|
||||
# convert module parameters to realm representation parameters (if they belong in there)
|
||||
params_to_ignore = list(keycloak_argument_spec().keys()) + ['state']
|
||||
realm_params = [x for x in module.params
|
||||
if x not in params_to_ignore and
|
||||
module.params.get(x) is not None]
|
||||
|
||||
# See whether the realm already exists in Keycloak
|
||||
before_realm = kc.get_realm_by_id(realm=realm) or {}
|
||||
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = dict()
|
||||
|
||||
for realm_param in realm_params:
|
||||
new_param_value = module.params.get(realm_param)
|
||||
changeset[camel(realm_param)] = new_param_value
|
||||
|
||||
# Whether creating or updating a realm, take the before-state and merge the changeset into it
|
||||
updated_realm = before_realm.copy()
|
||||
updated_realm.update(changeset)
|
||||
|
||||
result['proposed'] = sanitize_cr(changeset)
|
||||
before_realm_sanitized = sanitize_cr(before_realm)
|
||||
result['existing'] = before_realm_sanitized
|
||||
|
||||
# If the realm does not exist yet, before_realm is still empty
|
||||
if not before_realm:
|
||||
if state == 'absent':
|
||||
# do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['msg'] = 'Realm does not exist, doing nothing.'
|
||||
module.exit_json(**result)
|
||||
|
||||
# create new realm
|
||||
result['changed'] = True
|
||||
if 'id' not in updated_realm:
|
||||
module.fail_json(msg='id needs to be specified when creating a new realm')
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize_cr(updated_realm))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.create_realm(updated_realm)
|
||||
after_realm = kc.get_realm_by_id(updated_realm['id'])
|
||||
|
||||
result['end_state'] = sanitize_cr(after_realm)
|
||||
|
||||
result['msg'] = 'Realm %s has been created.' % updated_realm['id']
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
if state == 'present':
|
||||
# update existing realm
|
||||
result['changed'] = True
|
||||
if module.check_mode:
|
||||
# We can only compare the current realm with the proposed updates we have
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_realm_sanitized,
|
||||
after=sanitize_cr(updated_realm))
|
||||
result['changed'] = (before_realm != updated_realm)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.update_realm(updated_realm, realm=realm)
|
||||
|
||||
after_realm = kc.get_realm_by_id(realm=realm)
|
||||
if before_realm == after_realm:
|
||||
result['changed'] = False
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_realm_sanitized,
|
||||
after=sanitize_cr(after_realm))
|
||||
result['end_state'] = sanitize_cr(after_realm)
|
||||
|
||||
result['msg'] = 'Realm %s has been updated.' % updated_realm['id']
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
# Delete existing realm
|
||||
result['changed'] = True
|
||||
if module._diff:
|
||||
result['diff']['before'] = before_realm_sanitized
|
||||
result['diff']['after'] = ''
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.delete_realm(realm=realm)
|
||||
result['proposed'] = dict()
|
||||
result['end_state'] = dict()
|
||||
result['msg'] = 'Realm %s has been deleted.' % before_realm['id']
|
||||
module.exit_json(**result)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue