Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PR #5024/88a3daf2 backport][stable-5] Fix: Add user-agent header to allow request through WAF with bot protection #5046

Conversation

patchback[bot]
Copy link

@patchback patchback bot commented Aug 1, 2022

This is a backport of PR #5024 as merged into main (88a3daf).

SUMMARY

When keycloak is running behind WAF or CDN, (.e.g Cloudflare with DNS Proxy) Requests with no User-Agent get status code 403 Forbidden.

Fixes #5023

ISSUE TYPE
  • Bugfix Pull Request
COMPONENT NAME

module_utils/identity/keycloak

ADDITIONAL INFORMATION

When Keycloak is running behind a CDN/WAF, absence of use-agent gets considered as bot request and hence return 403 Forbidden

Before Change

TASK [keycloakrealm : Create or update Keycloak realm (minimal example)] ****************************************************************************************************************
task path: /home/dishant/Projects/grist/keycloak-ansible/keycloakrealm/tasks/main.yml:34
redirecting (type: modules) community.general.keycloak_realm to community.general.identity.keycloak.keycloak_realm
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: dishant
<127.0.0.1> EXEC /bin/sh -c 'echo ~dishant && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/dishant/.ansible/tmp `"&& mkdir "` echo /home/dishant/.ansible/tmp/ansible-tmp-1659033296.2615469-369090-46313507833545 `" && echo ansible-tmp-1659033296.2615469-369090-46313507833545="` echo /home/dishant/.ansible/tmp/ansible-tmp-1659033296.2615469-369090-46313507833545 `" ) && sleep 0'
redirecting (type: modules) community.general.keycloak_realm to community.general.identity.keycloak.keycloak_realm
Using module file /home/dishant/.ansible/collections/ansible_collections/community/general/plugins/modules/identity/keycloak/keycloak_realm.py
<127.0.0.1> PUT /home/dishant/.ansible/tmp/ansible-local-368771m5ibb0wr/tmp9emwij4y TO /home/dishant/.ansible/tmp/ansible-tmp-1659033296.2615469-369090-46313507833545/AnsiballZ_keycloak_realm.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/dishant/.ansible/tmp/ansible-tmp-1659033296.2615469-369090-46313507833545/ /home/dishant/.ansible/tmp/ansible-tmp-1659033296.2615469-369090-46313507833545/AnsiballZ_keycloak_realm.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3 /home/dishant/.ansible/tmp/ansible-tmp-1659033296.2615469-369090-46313507833545/AnsiballZ_keycloak_realm.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/dishant/.ansible/tmp/ansible-tmp-1659033296.2615469-369090-46313507833545/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
  File "/tmp/ansible_community.general.keycloak_realm_payload_mtp2yy2v/ansible_community.general.keycloak_realm_payload.zip/ansible_collections/community/general/plugins/modules/identity/keycloak/keycloak_realm.py", line 695, in main
  File "/tmp/ansible_community.general.keycloak_realm_payload_mtp2yy2v/ansible_community.general.keycloak_realm_payload.zip/ansible_collections/community/general/plugins/module_utils/identity/keycloak/keycloak.py", line 160, in get_token
    raise KeycloakError('Could not obtain access token from %s: %s'
fatal: [localhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "access_code_lifespan": null,
            "access_code_lifespan_login": null,
            "access_code_lifespan_user_action": null,
            "access_token_lifespan": null,
            "access_token_lifespan_for_implicit_flow": null,
            "account_theme": null,
            "action_token_generated_by_admin_lifespan": null,
            "action_token_generated_by_user_lifespan": null,
            "admin_events_details_enabled": null,
            "admin_events_enabled": null,
            "admin_theme": null,
            "attributes": null,
            "auth_client_id": "********-cli",
            "auth_client_secret": null,
            "auth_keycloak_url": "https://kc.korifi.run",
            "auth_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "auth_realm": "master",
            "auth_username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "browser_flow": null,
            "browser_security_headers": null,
            "brute_force_protected": null,
            "client_authentication_flow": null,
            "client_scope_mappings": null,
            "connection_timeout": 10,
            "default_default_client_scopes": null,
            "default_groups": null,
            "default_locale": null,
            "default_optional_client_scopes": null,
            "default_roles": null,
            "default_signature_algorithm": null,
            "direct_grant_flow": null,
            "display_name": null,
            "display_name_html": null,
            "docker_authentication_flow": null,
            "duplicate_emails_allowed": null,
            "edit_username_allowed": null,
            "email_theme": null,
            "enabled": null,
            "enabled_event_types": null,
            "events_enabled": null,
            "events_expiration": null,
            "events_listeners": null,
            "failure_factor": null,
            "id": "demo",
            "internationalization_enabled": null,
            "login_theme": null,
            "login_with_email_allowed": null,
            "max_delta_time_seconds": null,
            "max_failure_wait_seconds": null,
            "minimum_quick_login_wait_seconds": null,
            "not_before": null,
            "offline_session_idle_timeout": null,
            "offline_session_max_lifespan": null,
            "offline_session_max_lifespan_enabled": null,
            "otp_policy_algorithm": null,
            "otp_policy_digits": null,
            "otp_policy_initial_counter": null,
            "otp_policy_look_ahead_window": null,
            "otp_policy_period": null,
            "otp_policy_type": null,
            "otp_supported_applications": null,
            "password_policy": null,
            "permanent_lockout": null,
            "quick_login_check_milli_seconds": null,
            "realm": "demo",
            "refresh_token_max_reuse": null,
            "registration_allowed": null,
            "registration_email_as_username": null,
            "registration_flow": null,
            "remember_me": null,
            "reset_credentials_flow": null,
            "reset_password_allowed": null,
            "revoke_refresh_token": null,
            "smtp_server": null,
            "ssl_required": null,
            "sso_session_idle_timeout": null,
            "sso_session_idle_timeout_remember_me": null,
            "sso_session_max_lifespan": null,
            "sso_session_max_lifespan_remember_me": null,
            "state": "present",
            "supported_locales": null,
            "token": null,
            "user_managed_access_allowed": null,
            "validate_certs": false,
            "verify_email": null,
            "wait_increment_seconds": null
        }
    },
    "msg": "Could not obtain access token from https://kc.korifi.run/realms/master/protocol/openid-connect/token: HTTP Error 403: Forbidden"
}

After Change

TASK [keycloakrealm : Create or update Keycloak realm (minimal example)] ****************************************************************************************************************
task path: /home/dishant/Projects/grist/keycloak-ansible/keycloakrealm/tasks/main.yml:34
redirecting (type: modules) community.general.keycloak_realm to community.general.identity.keycloak.keycloak_realm
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: dishant
<127.0.0.1> EXEC /bin/sh -c 'echo ~dishant && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/dishant/.ansible/tmp `"&& mkdir "` echo /home/dishant/.ansible/tmp/ansible-tmp-1659033443.2723455-371110-261240589444637 `" && echo ansible-tmp-1659033443.2723455-371110-261240589444637="` echo /home/dishant/.ansible/tmp/ansible-tmp-1659033443.2723455-371110-261240589444637 `" ) && sleep 0'
redirecting (type: modules) community.general.keycloak_realm to community.general.identity.keycloak.keycloak_realm
Using module file /home/dishant/.ansible/collections/ansible_collections/community/general/plugins/modules/identity/keycloak/keycloak_realm.py
<127.0.0.1> PUT /home/dishant/.ansible/tmp/ansible-local-370868g33w3t86/tmpz449juj8 TO /home/dishant/.ansible/tmp/ansible-tmp-1659033443.2723455-371110-261240589444637/AnsiballZ_keycloak_realm.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/dishant/.ansible/tmp/ansible-tmp-1659033443.2723455-371110-261240589444637/ /home/dishant/.ansible/tmp/ansible-tmp-1659033443.2723455-371110-261240589444637/AnsiballZ_keycloak_realm.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3 /home/dishant/.ansible/tmp/ansible-tmp-1659033443.2723455-371110-261240589444637/AnsiballZ_keycloak_realm.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/dishant/.ansible/tmp/ansible-tmp-1659033443.2723455-371110-261240589444637/ > /dev/null 2>&1 && sleep 0'
ok: [localhost] => {
    "changed": false,
    "diff": {},
    "end_state": {
        "accessCodeLifespan": 60,
        "accessCodeLifespanLogin": 1800,
        "accessCodeLifespanUserAction": 300,
        "accessTokenLifespan": 300,
        "accessTokenLifespanForImplicitFlow": 900,
        "actionTokenGeneratedByAdminLifespan": 43200,
        "actionTokenGeneratedByUserLifespan": 300,
        "adminEventsDetailsEnabled": false,
        "adminEventsEnabled": false,
        "attributes": {
            "cibaAuthRequestedUserHint": "login_hint",
            "cibaBackchannelTokenDeliveryMode": "poll",
            "cibaExpiresIn": "120",
            "cibaInterval": "5",
            "clientOfflineSessionIdleTimeout": "0",
            "clientOfflineSessionMaxLifespan": "0",
            "clientSessionIdleTimeout": "0",
            "clientSessionMaxLifespan": "0",
            "oauth2DeviceCodeLifespan": "600",
            "oauth2DevicePollingInterval": "5",
            "parRequestUriLifespan": "60"
        },
        "browserFlow": "browser",
        "browserSecurityHeaders": {
            "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
            "contentSecurityPolicyReportOnly": "",
            "strictTransportSecurity": "max-age=31536000; includeSubDomains",
            "xContentTypeOptions": "nosniff",
            "xFrameOptions": "SAMEORIGIN",
            "xRobotsTag": "none",
            "xXSSProtection": "1; mode=block"
        },
        "bruteForceProtected": false,
        "clientAuthenticationFlow": "clients",
        "clientOfflineSessionIdleTimeout": 0,
        "clientOfflineSessionMaxLifespan": 0,
        "clientPolicies": {
            "policies": []
        },
        "clientProfiles": {
            "profiles": []
        },
        "clientSessionIdleTimeout": 0,
        "clientSessionMaxLifespan": 0,
        "defaultRole": {
            "clientRole": false,
            "composite": true,
            "containerId": "demo",
            "description": "${role_default-roles}",
            "id": "8d4d2b6e-5281-4bee-9ec0-fbfcbc91d422",
            "name": "default-roles-demo"
        },
        "defaultSignatureAlgorithm": "RS256",
        "directGrantFlow": "direct grant",
        "dockerAuthenticationFlow": "docker auth",
        "duplicateEmailsAllowed": false,
        "editUsernameAllowed": false,
        "enabled": false,
        "enabledEventTypes": [],
        "eventsEnabled": false,
        "eventsListeners": [
            "jboss-logging"
        ],
        "failureFactor": 30,
        "id": "demo",
        "identityProviderMappers": [],
        "identityProviders": [],
        "internationalizationEnabled": false,
        "loginWithEmailAllowed": true,
        "maxDeltaTimeSeconds": 43200,
        "maxFailureWaitSeconds": 900,
        "minimumQuickLoginWaitSeconds": 60,
        "notBefore": 0,
        "oauth2DeviceCodeLifespan": 600,
        "oauth2DevicePollingInterval": 5,
        "offlineSessionIdleTimeout": 2592000,
        "offlineSessionMaxLifespan": 5184000,
        "offlineSessionMaxLifespanEnabled": false,
        "otpPolicyAlgorithm": "HmacSHA1",
        "otpPolicyDigits": 6,
        "otpPolicyInitialCounter": 0,
        "otpPolicyLookAheadWindow": 1,
        "otpPolicyPeriod": 30,
        "otpPolicyType": "totp",
        "otpSupportedApplications": [
            "FreeOTP",
            "Google Authenticator"
        ],
        "permanentLockout": false,
        "quickLoginCheckMilliSeconds": 1000,
        "realm": "demo",
        "refreshTokenMaxReuse": 0,
        "registrationAllowed": false,
        "registrationEmailAsUsername": false,
        "registrationFlow": "registration",
        "rememberMe": false,
        "requiredCredentials": [
            "password"
        ],
        "resetCredentialsFlow": "reset credentials",
        "resetPasswordAllowed": false,
        "revokeRefreshToken": false,
        "smtpServer": {},
        "sslRequired": "external",
        "ssoSessionIdleTimeout": 1800,
        "ssoSessionIdleTimeoutRememberMe": 0,
        "ssoSessionMaxLifespan": 36000,
        "ssoSessionMaxLifespanRememberMe": 0,
        "supportedLocales": [],
        "userManagedAccessAllowed": false,
        "verifyEmail": false,
        "waitIncrementSeconds": 60,
        "webAuthnPolicyAcceptableAaguids": [],
        "webAuthnPolicyAttestationConveyancePreference": "not specified",
        "webAuthnPolicyAuthenticatorAttachment": "not specified",
        "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
        "webAuthnPolicyCreateTimeout": 0,
        "webAuthnPolicyPasswordlessAcceptableAaguids": [],
        "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
        "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
        "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
        "webAuthnPolicyPasswordlessCreateTimeout": 0,
        "webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
        "webAuthnPolicyPasswordlessRpEntityName": "keycloak",
        "webAuthnPolicyPasswordlessRpId": "",
        "webAuthnPolicyPasswordlessSignatureAlgorithms": [
            "ES256"
        ],
        "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
        "webAuthnPolicyRequireResidentKey": "not specified",
        "webAuthnPolicyRpEntityName": "keycloak",
        "webAuthnPolicyRpId": "",
        "webAuthnPolicySignatureAlgorithms": [
            "ES256"
        ],
        "webAuthnPolicyUserVerificationRequirement": "not specified"
    },
    "existing": {
        "accessCodeLifespan": 60,
        "accessCodeLifespanLogin": 1800,
        "accessCodeLifespanUserAction": 300,
        "accessTokenLifespan": 300,
        "accessTokenLifespanForImplicitFlow": 900,
        "actionTokenGeneratedByAdminLifespan": 43200,
        "actionTokenGeneratedByUserLifespan": 300,
        "adminEventsDetailsEnabled": false,
        "adminEventsEnabled": false,
        "attributes": {
            "cibaAuthRequestedUserHint": "login_hint",
            "cibaBackchannelTokenDeliveryMode": "poll",
            "cibaExpiresIn": "120",
            "cibaInterval": "5",
            "clientOfflineSessionIdleTimeout": "0",
            "clientOfflineSessionMaxLifespan": "0",
            "clientSessionIdleTimeout": "0",
            "clientSessionMaxLifespan": "0",
            "oauth2DeviceCodeLifespan": "600",
            "oauth2DevicePollingInterval": "5",
            "parRequestUriLifespan": "60"
        },
        "browserFlow": "browser",
        "browserSecurityHeaders": {
            "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
            "contentSecurityPolicyReportOnly": "",
            "strictTransportSecurity": "max-age=31536000; includeSubDomains",
            "xContentTypeOptions": "nosniff",
            "xFrameOptions": "SAMEORIGIN",
            "xRobotsTag": "none",
            "xXSSProtection": "1; mode=block"
        },
        "bruteForceProtected": false,
        "clientAuthenticationFlow": "clients",
        "clientOfflineSessionIdleTimeout": 0,
        "clientOfflineSessionMaxLifespan": 0,
        "clientPolicies": {
            "policies": []
        },
        "clientProfiles": {
            "profiles": []
        },
        "clientSessionIdleTimeout": 0,
        "clientSessionMaxLifespan": 0,
        "defaultRole": {
            "clientRole": false,
            "composite": true,
            "containerId": "demo",
            "description": "${role_default-roles}",
            "id": "8d4d2b6e-5281-4bee-9ec0-fbfcbc91d422",
            "name": "default-roles-demo"
        },
        "defaultSignatureAlgorithm": "RS256",
        "directGrantFlow": "direct grant",
        "dockerAuthenticationFlow": "docker auth",
        "duplicateEmailsAllowed": false,
        "editUsernameAllowed": false,
        "enabled": false,
        "enabledEventTypes": [],
        "eventsEnabled": false,
        "eventsListeners": [
            "jboss-logging"
        ],
        "failureFactor": 30,
        "id": "demo",
        "identityProviderMappers": [],
        "identityProviders": [],
        "internationalizationEnabled": false,
        "loginWithEmailAllowed": true,
        "maxDeltaTimeSeconds": 43200,
        "maxFailureWaitSeconds": 900,
        "minimumQuickLoginWaitSeconds": 60,
        "notBefore": 0,
        "oauth2DeviceCodeLifespan": 600,
        "oauth2DevicePollingInterval": 5,
        "offlineSessionIdleTimeout": 2592000,
        "offlineSessionMaxLifespan": 5184000,
        "offlineSessionMaxLifespanEnabled": false,
        "otpPolicyAlgorithm": "HmacSHA1",
        "otpPolicyDigits": 6,
        "otpPolicyInitialCounter": 0,
        "otpPolicyLookAheadWindow": 1,
        "otpPolicyPeriod": 30,
        "otpPolicyType": "totp",
        "otpSupportedApplications": [
            "FreeOTP",
            "Google Authenticator"
        ],
        "permanentLockout": false,
        "quickLoginCheckMilliSeconds": 1000,
        "realm": "demo",
        "refreshTokenMaxReuse": 0,
        "registrationAllowed": false,
        "registrationEmailAsUsername": false,
        "registrationFlow": "registration",
        "rememberMe": false,
        "requiredCredentials": [
            "password"
        ],
        "resetCredentialsFlow": "reset credentials",
        "resetPasswordAllowed": false,
        "revokeRefreshToken": false,
        "smtpServer": {},
        "sslRequired": "external",
        "ssoSessionIdleTimeout": 1800,
        "ssoSessionIdleTimeoutRememberMe": 0,
        "ssoSessionMaxLifespan": 36000,
        "ssoSessionMaxLifespanRememberMe": 0,
        "supportedLocales": [],
        "userManagedAccessAllowed": false,
        "verifyEmail": false,
        "waitIncrementSeconds": 60,
        "webAuthnPolicyAcceptableAaguids": [],
        "webAuthnPolicyAttestationConveyancePreference": "not specified",
        "webAuthnPolicyAuthenticatorAttachment": "not specified",
        "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
        "webAuthnPolicyCreateTimeout": 0,
        "webAuthnPolicyPasswordlessAcceptableAaguids": [],
        "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
        "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
        "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
        "webAuthnPolicyPasswordlessCreateTimeout": 0,
        "webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
        "webAuthnPolicyPasswordlessRpEntityName": "keycloak",
        "webAuthnPolicyPasswordlessRpId": "",
        "webAuthnPolicyPasswordlessSignatureAlgorithms": [
            "ES256"
        ],
        "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
        "webAuthnPolicyRequireResidentKey": "not specified",
        "webAuthnPolicyRpEntityName": "keycloak",
        "webAuthnPolicyRpId": "",
        "webAuthnPolicySignatureAlgorithms": [
            "ES256"
        ],
        "webAuthnPolicyUserVerificationRequirement": "not specified"
    },
    "invocation": {
        "module_args": {
            "access_code_lifespan": null,
            "access_code_lifespan_login": null,
            "access_code_lifespan_user_action": null,
            "access_token_lifespan": null,
            "access_token_lifespan_for_implicit_flow": null,
            "account_theme": null,
            "action_token_generated_by_admin_lifespan": null,
            "action_token_generated_by_user_lifespan": null,
            "admin_events_details_enabled": null,
            "admin_events_enabled": null,
            "admin_theme": null,
            "attributes": null,
            "auth_client_id": "********-cli",
            "auth_client_secret": null,
            "auth_keycloak_url": "https://kc.korifi.run",
            "auth_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "auth_realm": "master",
            "auth_username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "browser_flow": null,
            "browser_security_headers": null,
            "brute_force_protected": null,
            "client_authentication_flow": null,
            "client_scope_mappings": null,
            "connection_timeout": 10,
            "default_default_client_scopes": null,
            "default_groups": null,
            "default_locale": null,
            "default_optional_client_scopes": null,
            "default_roles": null,
            "default_signature_algorithm": null,
            "direct_grant_flow": null,
            "display_name": null,
            "display_name_html": null,
            "docker_authentication_flow": null,
            "duplicate_emails_allowed": null,
            "edit_username_allowed": null,
            "email_theme": null,
            "enabled": null,
            "enabled_event_types": null,
            "events_enabled": null,
            "events_expiration": null,
            "events_listeners": null,
            "failure_factor": null,
            "id": "demo",
            "internationalization_enabled": null,
            "login_theme": null,
            "login_with_email_allowed": null,
            "max_delta_time_seconds": null,
            "max_failure_wait_seconds": null,
            "minimum_quick_login_wait_seconds": null,
            "not_before": null,
            "offline_session_idle_timeout": null,
            "offline_session_max_lifespan": null,
            "offline_session_max_lifespan_enabled": null,
            "otp_policy_algorithm": null,
            "otp_policy_digits": null,
            "otp_policy_initial_counter": null,
            "otp_policy_look_ahead_window": null,
            "otp_policy_period": null,
            "otp_policy_type": null,
            "otp_supported_applications": null,
            "password_policy": null,
            "permanent_lockout": null,
            "quick_login_check_milli_seconds": null,
            "realm": "demo",
            "refresh_token_max_reuse": null,
            "registration_allowed": null,
            "registration_email_as_username": null,
            "registration_flow": null,
            "remember_me": null,
            "reset_credentials_flow": null,
            "reset_password_allowed": null,
            "revoke_refresh_token": null,
            "smtp_server": null,
            "ssl_required": null,
            "sso_session_idle_timeout": null,
            "sso_session_idle_timeout_remember_me": null,
            "sso_session_max_lifespan": null,
            "sso_session_max_lifespan_remember_me": null,
            "state": "present",
            "supported_locales": null,
            "token": null,
            "user_managed_access_allowed": null,
            "validate_certs": false,
            "verify_email": null,
            "wait_increment_seconds": null
        }
    },
    "msg": "Realm demo has been updated.",
    "proposed": {
        "id": "demo",
        "realm": "demo"
    }
}

…ection (#5024)

* Fix: Add user agent header to allow request through CDN/WAF with bot protection

* upate doc-fragment

* move http_agent variable assignment

* set http_agent param for all Keycloak API Requests

* Update plugins/doc_fragments/keycloak.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update changelogs/fragments/5023-http-agent-param-keycloak.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* fix formatting

* Update plugins/doc_fragments/keycloak.py

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 88a3daf)
@ansibullbot
Copy link
Collaborator

@ansibullbot ansibullbot added backport bug This issue/PR relates to a bug docs_fragments docs_fragments plugin (shared docs) identity module_utils module_utils new_contributor Help guide this first time contributor plugins plugin (any type) traceback labels Aug 1, 2022
@felixfontein felixfontein merged commit 9358640 into stable-5 Aug 1, 2022
@felixfontein felixfontein deleted the patchback/backports/stable-5/88a3daf2ec933fa7224f085d1ea97d34bab3c314/pr-5024 branch August 1, 2022 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue/PR relates to a bug docs_fragments docs_fragments plugin (shared docs) identity module_utils module_utils new_contributor Help guide this first time contributor plugins plugin (any type) traceback
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants