diff --git a/auth_oidc_logout/__init__.py b/auth_oidc_logout/__init__.py new file mode 100644 index 0000000000..7f46cabe82 --- /dev/null +++ b/auth_oidc_logout/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2016 ICTSTUDIO +# License: AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from . import controllers diff --git a/auth_oidc_logout/__manifest__.py b/auth_oidc_logout/__manifest__.py new file mode 100644 index 0000000000..efd32dd2e7 --- /dev/null +++ b/auth_oidc_logout/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2016 ICTSTUDIO +# Copyright 2021 ACSONE SA/NV +# License: AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +{ + "name": "Authentication OpenID Connect Logout process", + "version": "16.0.0.1.0", + "license": "AGPL-3", + "author": ( + "ICTSTUDIO, André Schenkels, ACSONE SA/NV, Odoo Community Association (OCA)" + ), + "maintainers": ["sbidoul"], + "website": "https://github.com/OCA/server-auth", + "summary": "Allow users to login through OpenID Connect Provider", + "external_dependencies": {"python": ["python-jose"]}, + "depends": ["auth_oidc"], + "data": [], + "demo": [], +} diff --git a/auth_oidc_logout/controllers/__init__.py b/auth_oidc_logout/controllers/__init__.py new file mode 100644 index 0000000000..eaa83817e9 --- /dev/null +++ b/auth_oidc_logout/controllers/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2016 ICTSTUDIO +# License: AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from . import main diff --git a/auth_oidc_logout/controllers/main.py b/auth_oidc_logout/controllers/main.py new file mode 100644 index 0000000000..d25a8911d4 --- /dev/null +++ b/auth_oidc_logout/controllers/main.py @@ -0,0 +1,36 @@ +# Copyright 2016 ICTSTUDIO +# Copyright 2021 ACSONE SA/NV +# License: AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +from urllib.parse import parse_qs, urljoin, urlparse + +from werkzeug.urls import url_encode + +from odoo import http +from odoo.http import request + +from odoo.addons.web.controllers.session import Session + + +class OpenIDLogout(Session): + @http.route("/web/session/logout", type="http", auth="none") + def logout(self, redirect="/web/login"): + # https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout + user = request.env["res.users"].sudo().browse(request.session.uid) + if user.oauth_provider_id.id: + provider = ( + request.env["auth.oauth.provider"] + .sudo() + .browse(user.oauth_provider_id.id) + ) + if provider.end_session_endpoint: + redirect_url = urljoin(request.httprequest.url_root, redirect) + components = urlparse(provider.end_session_endpoint) + params = parse_qs(components.query) + params["client_id"] = provider.client_id + params["post_logout_redirect_uri"] = redirect_url + logout_url = components._replace(query=url_encode(params)).geturl() + # Override the session logout to allow a non local redirect + request.session.logout(keep_db=True) + return request.env["ir.http"]._redirect(logout_url, 303) + # User has no account with any provider or no logout URL is configured for the provider + return super().logout(redirect=redirect) diff --git a/auth_oidc_logout/tests/__init__.py b/auth_oidc_logout/tests/__init__.py new file mode 100644 index 0000000000..cc8faf72bf --- /dev/null +++ b/auth_oidc_logout/tests/__init__.py @@ -0,0 +1 @@ +from . import test_auth_oidc_logout diff --git a/auth_oidc_logout/tests/keycloak/keycloak-config.json b/auth_oidc_logout/tests/keycloak/keycloak-config.json new file mode 100644 index 0000000000..5a0456b55c --- /dev/null +++ b/auth_oidc_logout/tests/keycloak/keycloak-config.json @@ -0,0 +1,1997 @@ +{ + "id": "master", + "realm": "master", + "displayName": "Keycloak", + "displayNameHtml": "
Keycloak
", + "notBefore": 0, + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 60, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "39f27ebe-139e-435b-840a-beb824d5d355", + "name": "admin", + "description": "${role_admin}", + "composite": true, + "composites": { + "realm": ["create-realm"], + "client": { + "master-realm": [ + "create-client", + "view-realm", + "view-events", + "manage-clients", + "query-clients", + "view-identity-providers", + "impersonation", + "manage-events", + "query-realms", + "query-groups", + "manage-authorization", + "query-users", + "view-authorization", + "manage-identity-providers", + "manage-users", + "view-clients", + "view-users", + "manage-realm" + ] + } + }, + "clientRole": false, + "containerId": "master", + "attributes": {} + }, + { + "id": "3fd38fac-f708-4783-b8e9-4e47963fc4bf", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "master", + "attributes": {} + }, + { + "id": "4ac4a81b-0a30-41db-94ce-dbd621c331d2", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "master", + "attributes": {} + }, + { + "id": "20b16986-2361-454c-af0b-81f403152ef8", + "name": "create-realm", + "description": "${role_create-realm}", + "composite": false, + "clientRole": false, + "containerId": "master", + "attributes": {} + } + ], + "client": { + "auth_oidc-test": [], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "5fa108a0-2e5e-4e2e-8ee3-1317592517f8", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "d1dd5ade-20bf-4d53-a371-a33f10bc1087", + "attributes": {} + } + ], + "master-realm": [ + { + "id": "0d062a1c-5165-4ea5-b550-55d02ca86226", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "f5795bcb-ab2d-4a74-b954-51f335c21198", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "1c0e3231-db03-4b03-961f-32308318f4f1", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "ed9949d1-b11d-4742-b259-ee260f62f111", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "b29b494a-9cd4-4410-8d16-207a3bb2e528", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "8afdd284-070b-4d6f-9d21-d9917d8827af", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "b5807416-f8f3-41ae-a29e-298ec3aae028", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "6400b20c-a72b-4228-87d1-01b0d1315026", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "6c3b14c3-0797-4e39-b5fa-b07d0e073e0e", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "3fbf2279-9661-4cfc-b381-c7e4a8c459dc", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "1b9e5572-34d5-4284-897c-0471544cf813", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "a226e0fa-aa45-490d-9d64-78e88c3152cb", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "d78736d4-250c-4012-a8ad-55b5c718a57a", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "68e9559f-d467-46c3-ae48-d67c74582ca8", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "908beec6-d8d1-441a-a5ad-f45d39df6b43", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "5c5d56a2-e2ea-4b4f-9bb1-f40e18082932", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "master-realm": ["query-clients"] + } + }, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "561ec0f4-bd97-4c41-a825-918002afb307", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "master-realm": ["query-groups", "query-users"] + } + }, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + }, + { + "id": "8ae350ac-19cd-431b-80fb-aee88316219e", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "attributes": {} + } + ], + "account": [ + { + "id": "0a6ac4dd-afdc-4b7b-b16a-ef2ca3b8e396", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "45ef915f-ca72-4bcc-a79b-d2b83ca4be2f", + "attributes": {} + }, + { + "id": "1a30b2d0-9d49-4a09-9769-ea7f3142e715", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": ["view-consent"] + } + }, + "clientRole": true, + "containerId": "45ef915f-ca72-4bcc-a79b-d2b83ca4be2f", + "attributes": {} + }, + { + "id": "e065f4ba-d97c-4219-b56e-edbe945e14bf", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "45ef915f-ca72-4bcc-a79b-d2b83ca4be2f", + "attributes": {} + }, + { + "id": "6e5b9a43-0f82-4669-a821-a1d449e4a2be", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "45ef915f-ca72-4bcc-a79b-d2b83ca4be2f", + "attributes": {} + }, + { + "id": "c386c8c5-bdee-4d52-b124-94379799d5d9", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "45ef915f-ca72-4bcc-a79b-d2b83ca4be2f", + "attributes": {} + }, + { + "id": "bcff49f4-7f83-4ec6-9a51-271fc9cbb302", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "45ef915f-ca72-4bcc-a79b-d2b83ca4be2f", + "attributes": {} + }, + { + "id": "4e36a4bf-80ab-404b-854e-7d593e9248ca", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": ["manage-account-links"] + } + }, + "clientRole": true, + "containerId": "45ef915f-ca72-4bcc-a79b-d2b83ca4be2f", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRoles": ["offline_access", "uma_authorization"], + "requiredCredentials": ["password"], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": ["FreeOTP", "Google Authenticator"], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": ["ES256"], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256"], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "users": [ + { + "id": "ad01a4d9-c919-4bc6-8b48-b3e3bcbb4149", + "createdTimestamp": 1618140941731, + "username": "admin", + "enabled": true, + "totp": false, + "emailVerified": false, + "credentials": [ + { + "id": "596b17bb-199c-4a23-9c48-4620c0ecfd7a", + "type": "password", + "createdDate": 1618140941876, + "secretData": "{\"value\":\"PXx46hQETQuXQRUl9FvzEJdZtoL57qsad1dFQyOLzj/pNEmwldN54oxQh5p+QB0rNNJPI9ZiaAfZS90ZzJa6pQ==\",\"salt\":\"kiFQwyPm53MgwAByqTw5qQ==\",\"additionalParameters\":{}}", + "credentialData": "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } + ], + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": ["offline_access", "admin", "uma_authorization"], + "clientRoles": { + "account": ["view-profile", "manage-account"] + }, + "notBefore": 0, + "groups": [] + }, + { + "id": "3752dfb8-d3b5-4597-b83c-fed005d2671c", + "createdTimestamp": 1618141153912, + "username": "demo", + "enabled": true, + "totp": false, + "emailVerified": false, + "credentials": [ + { + "id": "4e5b5a38-3fcb-4703-8b9c-075164dde145", + "type": "password", + "createdDate": 1618141311783, + "secretData": "{\"value\":\"upShAwzTaS89elSkEgK0Phs+XUP3Ya1pOUYtE8k4JmZEJnXWjdOy9brn4cpLKwjF6pZ3glxkJgjdLmDeWm9WwQ==\",\"salt\":\"RnaXCbRf4bw1lZmQX43cMg==\",\"additionalParameters\":{}}", + "credentialData": "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } + ], + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": ["offline_access", "uma_authorization"], + "clientRoles": { + "account": ["view-profile", "manage-account"] + }, + "notBefore": 0, + "groups": [] + } + ], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": ["offline_access"] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": ["manage-account"] + } + ] + }, + "clients": [ + { + "id": "45ef915f-ca72-4bcc-a79b-d2b83ca4be2f", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/master/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "055c06d1-ffcc-4762-b8eb-e9814a6995df", + "defaultRoles": ["view-profile", "manage-account"], + "redirectUris": ["/realms/master/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "role_list", "roles", "profile", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + }, + { + "id": "4308a071-7dbf-4d08-a987-b7dc2f42b86e", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/master/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "ec31839f-7ffb-400d-9373-26be6706e619", + "redirectUris": ["/realms/master/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "e36bba2d-7a07-4c83-a40e-14b4a8316ae9", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": ["web-origins", "role_list", "roles", "profile", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + }, + { + "id": "0915d9fc-102f-4033-b37e-832b89fee932", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "175303e4-f2d4-4ae9-8fb0-27a1337d3208", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "role_list", "roles", "profile", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + }, + { + "id": "8bf21eb5-63da-4da5-8c12-7a5bafda1bf5", + "clientId": "auth_oidc-test", + "rootUrl": "http://localhost:8069", + "adminUrl": "http://localhost:8069", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "20c0ad33-0200-43cd-9bd1-5dd1b22918e3", + "redirectUris": ["http://localhost:8069/*"], + "webOrigins": ["http://localhost:8069"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.assertion.signature": "false", + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "saml.encrypt": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "saml.server.signature": "false", + "saml.server.signature.keyinfo.ext": "false", + "exclude.session.state.from.auth.response": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "saml_force_name_id_format": "false", + "saml.client.signature": "false", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": ["web-origins", "role_list", "roles", "profile", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + }, + { + "id": "d1dd5ade-20bf-4d53-a371-a33f10bc1087", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "52aab659-5f2d-445a-a93e-6ab04de9db42", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "role_list", "roles", "profile", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + }, + { + "id": "4e03d0f9-4c56-42c8-958c-337f6eede3ac", + "clientId": "master-realm", + "name": "master Realm", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "15ca5d76-d964-4761-85d1-8343748481ab", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "role_list", "roles", "profile", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + }, + { + "id": "983b74a1-e7a0-4bc4-8481-0eb8ca4f12e0", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/master/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "121beec3-2388-475b-b989-1ff85d25b4fd", + "redirectUris": ["/admin/master/console/*"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "21a0f25a-a2b7-415e-95a7-23886f00c83b", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": ["web-origins", "role_list", "roles", "profile", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + } + ], + "clientScopes": [ + { + "id": "07bff9f2-498f-4f07-9fb9-019152141a0f", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "46333a31-1e88-4191-8d25-2f4d975af4db", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "8c30d3a8-af56-407a-a622-df16e7c2b04b", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "db1117e1-6174-4934-99d0-ff51f319c6f5", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "c1a7d21e-7f45-4559-b314-913cbb560967", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "3d9f47ed-d2f0-474c-baa4-75e0e6619385", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "e7c49c89-b513-4512-9410-bc0f39d4b4e5", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "7b65fe0b-2974-445f-a7cd-ccec5141f560", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "a9ed1a18-0e05-4eeb-a247-c84296cfa653", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "52f62f87-f914-4771-b79c-46a387797be7", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "d8c485dc-7b8a-4469-8868-5bb73a6abafa", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "b1b21cd7-06f7-4469-b11e-22bf9de1a3ce", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "311bf186-6cb2-4bdd-9da5-8ac30ff8b296", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "eda5d01f-6841-441e-b7d0-8fa48365a501", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "e131db35-e08b-4805-b11b-59a90650ee2a", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "6e311016-71e1-450a-8011-6f6ce9f7e365", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "e0fc1d75-2b19-4fc8-8ea3-778c96b47321", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "a94d4acf-0a46-44b0-a739-ed329dfa9f41", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "57d4c1ad-4507-4545-8efc-5f83c0dc0be6", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "0b42528f-d116-4217-9fbe-fe469c80914d", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "f698a281-a28c-4b3e-ad73-524c556d1cc5", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "50b2c4f9-b4a3-470a-a8e4-af7384bd9536", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "12a21276-1f49-4b34-8bf7-df4dd7929ebf", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "4abce20a-c47d-430a-85c0-f65cb9ae7aa0", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "fa7c99b6-9cdf-4f8f-96af-45df5f2497e2", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "983d7499-e23c-4971-9501-d404b405b484", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "f42b6bcb-4bac-44a8-8073-c3194b56029c", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "6acc2950-2bbe-49d8-b266-42e3c518f46f", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "8b0f3195-f1c2-4188-8045-5d48ba0aeb30", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "437e71e0-7728-4763-82af-29fd14b1fa12", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "d255020d-b385-417d-bf27-b3a8c5911579", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "5adb2a9c-5dbb-430c-89c0-9b464677245f", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "667e731f-4375-489f-bf03-566a7292719b", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "359211aa-1a6d-4441-a9bb-610acc6350db", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "6646f9a5-0a1e-4bcc-b1d1-35b035b5aa55", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "xXSSProtection": "1; mode=block", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": ["jboss-logging"], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "070f65ee-8d8f-4fff-ae32-a27016e7bf5c", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "81bc44f5-9bbd-4325-9f63-fc332e30e0e7", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-usermodel-property-mapper", + "saml-user-property-mapper", + "oidc-full-name-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-address-mapper", + "saml-user-attribute-mapper", + "saml-role-list-mapper" + ] + } + }, + { + "id": "f7d673f4-10ef-486d-a168-925b139abbc5", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "c103a051-9371-4021-8a34-8196a78c3638", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "a71eaf13-3e55-4aa6-9cf8-c1b74198d63a", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": ["true"], + "client-uris-must-match": ["true"] + } + }, + { + "id": "fb7bdacb-46bc-4266-b217-a1705e87f957", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-property-mapper", + "oidc-full-name-mapper", + "oidc-usermodel-property-mapper", + "oidc-address-mapper", + "saml-role-list-mapper" + ] + } + }, + { + "id": "ec4f12ef-2fef-42b2-9cb8-9f251d8c3344", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "99778abc-51f8-4480-a778-59ef73a60f56", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": ["200"] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "052d41cb-6938-40f0-8872-8ab171ec27e9", + "name": "fallback-HS256", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "kid": ["489fe44c-d70f-42f7-9a19-e3dc2a0df076"], + "secret": [ + "6dqvUhGU5rhuMOKNuOI4U7nPTcA9jeJJLpmoewnkw_PdFDSjy73iQkPt5hw_8qU34IIFGOM-LkJJ8VWihvwEwQ" + ], + "priority": ["-100"], + "algorithm": ["HS256"] + } + }, + { + "id": "53901ca8-2f9d-4f2e-804f-756204b9c1c5", + "name": "fallback-RS256", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "privateKey": [ + "MIIEpAIBAAKCAQEAgYNR3Pgh/f1+DUcMBc9T6uT1MwC4oTthGbtJhmqQiawSWzUO8icSM4hFjiN2zqsKx7ofWmP3+ZRTq6fSEref+0tRRWafTq6LtDySa4DilqnQ/WBznnXML9hmsPBW3gNiZAKYbwvb/YE36L+a4nWcEc13jcXgMqLXUD7K/3YIYNT/S7xGgNKYfBmbTfS0A08ZITtyakaGYwLK6zwLYVAeUj1hZjVcz1926Zhhu4YznD6qMgCmBwlSD9lc6v0/RUNjo1NKSU0LXAeUEk1ynxFKJ+cUikHuvsIQvuXY5Sj+Y2tcWFpU51J01com69kdyYeelQv1n41yOB/U4bGmbhUctwIDAQABAoIBAH+RgwwdmRXeH9AiQBRk8Gq5lU/kkPe3TmCTGsv8oVwKEpamP4+Drqj1vFVSV08gKOEsUn+tYm8CjBvTlNd86WcT+/xZJefRg6hH1Y1wiUAQCtvYqmnV7Abgp933Dglm2f5alB0lWE5ufkySlpQjdlQOx4js9HXL8juHblqMv5noJNaDQSDh4UxtET+fVT8pvCL/MImG4C6BtULLDXLdH4pIvn0OIS788Xpc87uc3dSIfVxL1Oa0U1Qrxma5P8p9imremKLdA4iOzopyVsLo0uP2PrSLWD04I9kSwO0MHNDzbkMJiWXX5a7afzRY4g+zQL2STYsbD4B9KQnIpsQNrVkCgYEA4LbUejeexUBsjs3Whkn1BlUvxvDf2Vtudws1XSNmd5lneitfseDXCcH6p1TLHn0xoOmJDFGjLPEYFhqL0I5IyZP6zfiCJL88zFWVXlY8NsAoQeqvgnu5wHpIXEXCaJAAksWy/dmUZwTUyfIIxnLUQMPpJ1stu35e8DyNO4VadPMCgYEAk4teFNWkFBZmjSBUyo8Tw4TmJuCIRVH4FSaspUeVNhToKI3e5R/duz8rvqBj4tul5lyWq9FmcDaawE94jIa17XQnj/O767G72lHRuIlI+qftIca3r4/kDvy730yAOWl/1Su4SrX3t7WSBHIG2j7HMYIsj5xgBUvnbRQUtxByui0CgYEAsLe3YyHoj3D5rlg708HHmqJVf1sgfxvDRIUhA0z6oSWX1eDUUdvi4H6XMw6g6ipEZCokJ/bvn0E+0usvduTeYwAn5eD/4AwwsPTBEb45fkkhn60DN1c7nh3MWBxYJcjRWpt1BuMcLOQEv4fC1OWq+//VlKjEz0UzPjQwUVWu7HcCgYAo6uqhfootY/T2yHObZUiG3ZFyUKyaBNx3CS2x/IMd53hm3slk44x7hE5eZF6vKFj+5MiIR99P2WTbVm7JEgbcHm1mV6LS/4xoRG6T7cbGdNGnn1OLpa0Klv6HM9EPmvlvpdtLJOHZGcqv3uuVlPlq+n3fKe/bKCy7LGl+R1p51QKBgQCEmPS9A9y6YF7zRo8u7vUmJzGktdrSw65zYZVMzXY9A7uKU/OfpZ+papKDr1D9ApFgi5Ip1imirR7K9m4GImowZOTe/E6dT6nmrUtWUkaS4ghhwZ9Gh6kAOWoBYRB/Z4XIzJoSiet+PJ3p8SLhM7nETj7IDaeQgNudSK8/ohNPWQ==" + ], + "certificate": [ + "MIICmzCCAYMCBgF4wLeSOTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjEwNDExMTEzNDE5WhcNMzEwNDExMTEzNTU5WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCBg1Hc+CH9/X4NRwwFz1Pq5PUzALihO2EZu0mGapCJrBJbNQ7yJxIziEWOI3bOqwrHuh9aY/f5lFOrp9ISt5/7S1FFZp9Orou0PJJrgOKWqdD9YHOedcwv2Gaw8FbeA2JkAphvC9v9gTfov5ridZwRzXeNxeAyotdQPsr/dghg1P9LvEaA0ph8GZtN9LQDTxkhO3JqRoZjAsrrPAthUB5SPWFmNVzPX3bpmGG7hjOcPqoyAKYHCVIP2Vzq/T9FQ2OjU0pJTQtcB5QSTXKfEUon5xSKQe6+whC+5djlKP5ja1xYWlTnUnTVyibr2R3Jh56VC/WfjXI4H9ThsaZuFRy3AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHEq+7bncqOh0RJJj+6fSHsIlkRGOeX6djVIKi1/eAJCD61Et3MHKh4kbu4U6phNlnhW5IFYinchGXe1uoG18fWkUS6QJoxHIDLR+tub7NSMraYxK85VgyLHCHaaGX7Bz+sIM628th4LlQd/M2zL45rqlMvB1XLxsMpi9Pb0Zc7qWwrvE5Jfi99UDAi6ZV3OojR6YC79HVHyOVmBIdLrVtn5mQYKJ5tF5F8xSs4ng96IO8Sn8pbUuYG8SlEz6KMmGH1sczlPE/3kAdm9IF+fXpYywuhsRNJyDBVDGpcqHTW+UW+V5TWa/ucZ6cpr1dQP5/FpcHylSWoXJpCk01PXl/M=" + ], + "priority": ["-100"], + "algorithm": ["RS256"] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "815c3100-241b-4298-8039-54253c2c7e70", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 20, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "e6a85d70-dc13-4705-9ba3-a980d548a430", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth-otp", + "requirement": "DISABLED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "96b14b20-7305-4018-8e75-86b572e3ace0", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "a51abcaa-7495-4526-997f-55cd82f152e2", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-otp", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "54fa7607-f4e5-4fe7-a8c3-4fad6ee376b8", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "31de3d9e-2f81-43cc-a4ad-1112cd4e9d71", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "Account verification options", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "f499a904-41cc-41c1-bb43-688672d1533b", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-otp", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "7cee4451-5b17-4742-8736-8fce85639409", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 20, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "dafe7404-bce7-4ab6-9e35-fd1aecb93545", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "CONDITIONAL", + "priority": 20, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "d34ac568-3793-4864-8df8-733fa2cd3554", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "identity-provider-redirector", + "requirement": "ALTERNATIVE", + "priority": 25, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "forms", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "15a43900-948a-487d-a97a-444502dce766", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-jwt", + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-secret-jwt", + "requirement": "ALTERNATIVE", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-x509", + "requirement": "ALTERNATIVE", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "1865917e-f56d-453c-bb66-578e1955d199", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-password", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "CONDITIONAL", + "priority": 30, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "3e151380-0869-4bdb-b9d1-65a7bcfcb6ab", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "79369bf2-9434-4b93-94d9-74a08a361701", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "User creation or linking", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "322d8eb9-a9cc-422a-a6a2-065b3b863967", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "CONDITIONAL", + "priority": 20, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "0cf68f4f-332e-4f7d-a7a9-907189914191", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "Authentication Options", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "d412906e-1aad-4707-ac40-95406aeed8d0", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "requirement": "REQUIRED", + "priority": 10, + "flowAlias": "registration form", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "d11ddacf-4fe8-4614-a9f1-fe5dcf621330", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-profile-action", + "requirement": "REQUIRED", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-password-action", + "requirement": "REQUIRED", + "priority": 50, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-recaptcha-action", + "requirement": "DISABLED", + "priority": 60, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "48093169-4a24-499b-aad7-b87dcd32269d", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-credential-email", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-password", + "requirement": "REQUIRED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "CONDITIONAL", + "priority": 40, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "f0a1d44c-2bab-408c-91b4-bb730bd65bc4", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "173229da-6a52-4d54-8e88-cba503234cb4", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "a72c2a36-a48a-440d-b52f-831c385287fc", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": {}, + "keycloakVersion": "12.0.4", + "userManagedAccessAllowed": false +} diff --git a/auth_oidc_logout/tests/keycloak/keycloak.sh b/auth_oidc_logout/tests/keycloak/keycloak.sh new file mode 100755 index 0000000000..7c81d562e7 --- /dev/null +++ b/auth_oidc_logout/tests/keycloak/keycloak.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -x +$(which docker || which podman) run --rm \ + -v $(dirname $0)/keycloak-config.json:/tmp/keycloak-config.json \ + -p 8080:8080 \ + quay.io/keycloak/keycloak:12.0.4 \ + -Dkeycloak.migration.action=import \ + -Dkeycloak.migration.provider=singleFile \ + -Dkeycloak.migration.file=/tmp/keycloak-config.json \ + -Dkeycloak.migration.strategy=OVERWRITE_EXISTING diff --git a/auth_oidc_logout/tests/test_auth_oidc_logout.py b/auth_oidc_logout/tests/test_auth_oidc_logout.py new file mode 100644 index 0000000000..349d3d7c0b --- /dev/null +++ b/auth_oidc_logout/tests/test_auth_oidc_logout.py @@ -0,0 +1,131 @@ +# Copyright 2021 ACSONE SA/NV +# License: AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import contextlib +import logging +from urllib.parse import parse_qsl, urljoin, urlparse + +from werkzeug.urls import url_encode + +import odoo +from odoo.tests import common +from odoo.tools.misc import DotDict + +from odoo.addons.website.tools import MockRequest + +from ..controllers.main import OpenIDLogout + +BASE_URL = "http://localhost:%s" % odoo.tools.config["http_port"] +CLIENT_ID = "auth_oidc-test" +LOGIN_PATH = "/web/login" +OIDC_BASE_LOGOUT_URL = "http://keycloak" +OIDC_LOGOUT_PATH = "/logout" + +logger = logging.getLogger(__name__) + + +@contextlib.contextmanager +def create_request(env, user_id, user_logout_func): + with MockRequest(env) as request: + request.httprequest.url_root = BASE_URL + "/" + request.session = DotDict(uid=user_id, logout=user_logout_func) + yield request + + +class TestOpenIDLogout(common.HttpCase): + @staticmethod + def mock_logout_user(keep_db): + logger.info("Logging out user in Odoo") + + def setUp(self): + super().setUp() + # search our test provider and bind the demo user to it + self.provider = self.env["auth.oauth.provider"].search( + [("client_id", "=", CLIENT_ID)], + limit=1, + ) + self.assertEqual(len(self.provider), 1) + + def _prepare_login_test_user(self, provider_id): + user = self.env.ref("base.user_demo") + user.write({"oauth_provider_id": provider_id, "oauth_uid": user.login}) + return user + + def _set_test_oidc_logout_url(self, end_session_endpoint): + self.provider.write({"end_session_endpoint": end_session_endpoint}) + + def test_skip_oidc_logout_for_user(self): + """Test that oidc logout is skipped if user is not associated to a provider""" + user = self._prepare_login_test_user(None) + with create_request(self.env, user.id, self.mock_logout_user): + resp = OpenIDLogout().logout() + self.assertEqual(LOGIN_PATH, resp.location) + + def test_skip_oidc_logout_for_all_users(self): + """Test that oidc logout is skipped for all users if provider has no logout url""" + self.assertFalse(self.provider.end_session_endpoint) + user = self._prepare_login_test_user(self.provider) + with create_request(self.env, user.id, self.mock_logout_user): + resp = OpenIDLogout().logout() + self.assertEqual(LOGIN_PATH, resp.location) + + def test_oidc_logout(self): + """Test that oidc logout""" + self._set_test_oidc_logout_url(urljoin(OIDC_BASE_LOGOUT_URL, OIDC_LOGOUT_PATH)) + user = self._prepare_login_test_user(self.provider) + with create_request(self.env, user.id, self.mock_logout_user): + resp = OpenIDLogout().logout() + self.assertTrue(resp.location.startswith(OIDC_BASE_LOGOUT_URL)) + actual_components = urlparse(resp.location) + self.assertEqual(OIDC_LOGOUT_PATH, actual_components.path) + actual_params = dict(parse_qsl(actual_components.query)) + self.assertEqual(CLIENT_ID, actual_params["client_id"]) + self.assertEqual( + urljoin(BASE_URL, LOGIN_PATH), actual_params["post_logout_redirect_uri"] + ) + + def test_oidc_logout_with_params(self): + """Test that params both in the logout and redirect urls are preserved""" + logout_url_params = {"param_1": 1, "param_2": 2} + oidc_logout_path = "{}?{}".format( + OIDC_LOGOUT_PATH, url_encode(logout_url_params) + ) + logout_url = urljoin(OIDC_BASE_LOGOUT_URL, oidc_logout_path) + self._set_test_oidc_logout_url(logout_url) + user = self._prepare_login_test_user(self.provider) + with create_request(self.env, user.id, self.mock_logout_user): + redirect_path = "{}?{}".format( + LOGIN_PATH, url_encode({"param_3": 3, "param_4": 4}) + ) + params = {} + params.update(logout_url_params) + params["client_id"] = CLIENT_ID + params["post_logout_redirect_uri"] = urljoin(BASE_URL, redirect_path) + resp = OpenIDLogout().logout(redirect_path) + self.assertTrue(resp.location.startswith(OIDC_BASE_LOGOUT_URL)) + actual_components = urlparse(resp.location) + self.assertEqual(OIDC_LOGOUT_PATH, actual_components.path) + actual_params = dict(parse_qsl(actual_components.query)) + self.assertEqual(CLIENT_ID, actual_params["client_id"]) + self.assertEqual("1", actual_params["param_1"]) + self.assertEqual("2", actual_params["param_2"]) + post_logout_url = actual_params["post_logout_redirect_uri"] + self.assertTrue(post_logout_url.startswith(BASE_URL)) + post_logout_components = urlparse(post_logout_url) + self.assertEqual(LOGIN_PATH, post_logout_components.path) + post_logout_params = dict(parse_qsl(post_logout_components.query)) + self.assertEqual("3", post_logout_params["param_3"]) + self.assertEqual("4", post_logout_params["param_4"]) + + def test_oidc_logout_with_absolute_redirect_url(self): + """Test that oidc logout allows an absolute redirect url""" + self._set_test_oidc_logout_url(urljoin(OIDC_BASE_LOGOUT_URL, OIDC_LOGOUT_PATH)) + user = self._prepare_login_test_user(self.provider) + with create_request(self.env, user.id, self.mock_logout_user): + resp = OpenIDLogout().logout(BASE_URL) + self.assertTrue(resp.location.startswith(OIDC_BASE_LOGOUT_URL)) + actual_components = urlparse(resp.location) + self.assertEqual(OIDC_LOGOUT_PATH, actual_components.path) + actual_params = dict(parse_qsl(actual_components.query)) + self.assertEqual(CLIENT_ID, actual_params["client_id"]) + self.assertEqual(BASE_URL, actual_params["post_logout_redirect_uri"]) diff --git a/setup/auth_oidc_logout/odoo/addons/auth_oidc_logout b/setup/auth_oidc_logout/odoo/addons/auth_oidc_logout new file mode 120000 index 0000000000..e1755ee2b3 --- /dev/null +++ b/setup/auth_oidc_logout/odoo/addons/auth_oidc_logout @@ -0,0 +1 @@ +../../../../auth_oidc_logout \ No newline at end of file diff --git a/setup/auth_oidc_logout/setup.py b/setup/auth_oidc_logout/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/auth_oidc_logout/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)