diff --git a/repository-dependencies/pom.xml b/repository-dependencies/pom.xml index 998bb60..7fcc35d 100644 --- a/repository-dependencies/pom.xml +++ b/repository-dependencies/pom.xml @@ -33,6 +33,11 @@ org.keycloak keycloak-adapter-core + + + com.sun.activation + * + org.bouncycastle * @@ -48,6 +53,11 @@ org.keycloak keycloak-servlet-adapter-spi + + + com.sun.activation + * + org.bouncycastle * @@ -56,6 +66,11 @@ com.fasterxml.jackson.core * + + + org.apache.httpcomponents + httpcomponents-client + @@ -63,6 +78,11 @@ org.keycloak keycloak-servlet-filter-adapter + + + com.sun.activation + * + org.bouncycastle * diff --git a/repository/src/main/config/log4j.properties b/repository/src/main/config/log4j.properties index 3733c5c..d64e80b 100644 --- a/repository/src/main/config/log4j.properties +++ b/repository/src/main/config/log4j.properties @@ -1,2 +1,4 @@ log4j.logger.${project.artifactId}=INFO -log4j.logger.${project.artifactId}.deps=ERROR \ No newline at end of file +log4j.logger.${project.artifactId}.deps=ERROR +log4j.logger.${project.artifactId}.deps.keycloak=ERROR +log4j.logger.${project.artifactId}.deps.jboss=ERROR \ No newline at end of file diff --git a/repository/src/main/config/module-context.xml b/repository/src/main/config/module-context.xml index 1daa95d..f5d03ed 100644 --- a/repository/src/main/config/module-context.xml +++ b/repository/src/main/config/module-context.xml @@ -75,7 +75,7 @@ - + diff --git a/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication-context.xml b/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication-context.xml index c26bc00..dbbdcf2 100644 --- a/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication-context.xml +++ b/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication-context.xml @@ -109,14 +109,21 @@ - + + + + + + + + - - + - + + diff --git a/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakAuthenticationFilter.java b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakAuthenticationFilter.java index bcac2f8..a34b470 100644 --- a/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakAuthenticationFilter.java +++ b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakAuthenticationFilter.java @@ -484,10 +484,6 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter final SessionUser sessionUser = this.createUserEnvironment(session, userId); this.keycloakAuthenticationComponent.handleUserTokens(accessToken, keycloakSecurityContext.getIdToken(), true); - // need different attribute name than default for integration with web scripts framework - // default attribute name seems to be no longer used - session.setAttribute(AuthenticationDriver.AUTHENTICATION_USER, sessionUser); - this.authenticationListener.userAuthenticated(new KeycloakCredentials(accessToken)); // store tokens in cache as well for ticket validation @@ -529,6 +525,41 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter chain.doFilter(requestWrapper, res); } + /** + * + * {@inheritDoc} + */ + @Override + protected SessionUser createUserEnvironment(final HttpSession session, final String userName) throws IOException, ServletException + { + final SessionUser sessionUser = super.createUserEnvironment(session, userName); + + // ensure all common attribute names are mapped + // Alfresco is really inconsistent with these attribute names + session.setAttribute(AuthenticationDriver.AUTHENTICATION_USER, sessionUser); + session.setAttribute(BaseAuthenticationFilter.AUTHENTICATION_USER, sessionUser); + + return sessionUser; + } + + /** + * + * {@inheritDoc} + */ + @Override + protected SessionUser createUserEnvironment(final HttpSession session, final String userName, final String ticket, + final boolean externalAuth) throws IOException, ServletException + { + final SessionUser sessionUser = super.createUserEnvironment(session, userName, ticket, externalAuth); + + // ensure all common attribute names are mapped + // Alfresco is really inconsistent with these attribute names + session.setAttribute(AuthenticationDriver.AUTHENTICATION_USER, sessionUser); + session.setAttribute(BaseAuthenticationFilter.AUTHENTICATION_USER, sessionUser); + + return sessionUser; + } + /** * Processes a failed authentication via Keycloak. * @@ -607,10 +638,6 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter LOGGER.trace("Skipping doFilter as filter is not active"); skip = true; } - else if (req.getAttribute(NO_AUTH_REQUIRED) != null) - { - LOGGER.trace("Skipping doFilter as filter higher up in chain determined authentication as not required"); - } else if (servletRequestUri.matches(KEYCLOAK_ACTION_URL_PATTERN)) { LOGGER.trace("Explicitly not skipping doFilter as Keycloak action URL is being called"); @@ -636,6 +663,14 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter else if (this.allowTicketLogon && this.checkForTicketParameter(context, req, res)) { LOGGER.trace("Skipping doFilter as user was authenticated by ticket URL parameter"); + skip = true; + } + // check no-auth flag (derived e.g. from checking if target web script requires authentication) only after all pre-emptive auth + // request details have been checked + else if (Boolean.TRUE.equals(req.getAttribute(NO_AUTH_REQUIRED))) + { + LOGGER.trace("Skipping doFilter as filter higher up in chain determined authentication as not required"); + skip = true; } else if (sessionUser != null) { diff --git a/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakWebScriptCookieAuthenticationFilter.java b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakWebScriptCookieAuthenticationFilter.java new file mode 100644 index 0000000..4168a8d --- /dev/null +++ b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakWebScriptCookieAuthenticationFilter.java @@ -0,0 +1,71 @@ +/* + * Copyright 2019 - 2020 Acosix GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.acosix.alfresco.keycloak.repo.authentication; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpSession; + +import org.alfresco.repo.SessionUser; +import org.alfresco.repo.webdav.auth.AuthenticationDriver; +import org.alfresco.repo.webdav.auth.BaseAuthenticationFilter; +import org.alfresco.web.app.servlet.WebscriptCookieAuthenticationFilter; + +/** + * This sub-class of the default web script cookie filter only exists to ensure the proper session attribute names are used for mapping the + * authenticated session user. + * + * @author Axel Faust + */ +public class KeycloakWebScriptCookieAuthenticationFilter extends WebscriptCookieAuthenticationFilter +{ + + /** + * + * {@inheritDoc} + */ + @Override + protected SessionUser createUserEnvironment(final HttpSession session, final String userName) throws IOException, ServletException + { + final SessionUser sessionUser = super.createUserEnvironment(session, userName); + + // ensure all common attribute names are mapped + // Alfresco is really inconsistent with these attribute names + session.setAttribute(AuthenticationDriver.AUTHENTICATION_USER, sessionUser); + session.setAttribute(BaseAuthenticationFilter.AUTHENTICATION_USER, sessionUser); + + return sessionUser; + } + + /** + * + * {@inheritDoc} + */ + @Override + protected SessionUser createUserEnvironment(final HttpSession session, final String userName, final String ticket, + final boolean externalAuth) throws IOException, ServletException + { + final SessionUser sessionUser = super.createUserEnvironment(session, userName, ticket, externalAuth); + + // ensure all common attribute names are mapped + // Alfresco is really inconsistent with these attribute names + session.setAttribute(AuthenticationDriver.AUTHENTICATION_USER, sessionUser); + session.setAttribute(BaseAuthenticationFilter.AUTHENTICATION_USER, sessionUser); + + return sessionUser; + } +} diff --git a/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakWebScriptSSOAuthenticationFilter.java b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakWebScriptSSOAuthenticationFilter.java new file mode 100644 index 0000000..fba39ce --- /dev/null +++ b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakWebScriptSSOAuthenticationFilter.java @@ -0,0 +1,147 @@ +/* + * Copyright 2019 - 2020 Acosix GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.acosix.alfresco.keycloak.repo.authentication; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.repo.management.subsystems.ActivateableBean; +import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter; +import org.alfresco.repo.webdav.auth.BaseAuthenticationFilter; +import org.alfresco.util.PropertyCheck; +import org.alfresco.web.app.servlet.WebScriptSSOAuthenticationFilter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.extensions.surf.util.URLDecoder; +import org.springframework.extensions.webscripts.Description.RequiredAuthentication; +import org.springframework.extensions.webscripts.Match; +import org.springframework.extensions.webscripts.RuntimeContainer; + +/** + * This web script SSO authentication filter class is used instead of {@link WebScriptSSOAuthenticationFilter default Alfresco filter} in + * order to properly handle unauthenticated and guest access, especially since the later is performed by Alfresco Share to load edition + * details and potentially other data needed for determining which customisations are active, even before a user has had a chance to + * authenticate. + * + * @author Axel Faust + */ +public class KeycloakWebScriptSSOAuthenticationFilter extends BaseAuthenticationFilter + implements DependencyInjectedFilter, InitializingBean, ActivateableBean +{ + + // copied from WebScriptRequestImpl due to accessible constraints + private static final String ARG_GUEST = "guest"; + + private static final Logger LOGGER = LoggerFactory.getLogger(KeycloakWebScriptSSOAuthenticationFilter.class); + + protected RuntimeContainer container; + + protected boolean isActive = true; + + /** + * + * {@inheritDoc} + */ + @Override + public void afterPropertiesSet() + { + PropertyCheck.mandatory(this, "container", this.container); + } + + /** + * @param container + * the container to set + */ + public void setContainer(final RuntimeContainer container) + { + this.container = container; + } + + /** + * Activates or deactivates the bean + * + * @param active + * true if the bean is active and initialisation should complete + */ + public final void setActive(final boolean active) + { + this.isActive = active; + } + + /** + * + * {@inheritDoc} + */ + @Override + public final boolean isActive() + { + return this.isActive; + } + + /** + * + * {@inheritDoc} + */ + @Override + public void doFilter(final ServletContext context, final ServletRequest sreq, final ServletResponse sresp, final FilterChain chain) + throws IOException, ServletException + { + final HttpServletRequest req = (HttpServletRequest) sreq; + + final String requestURI = req.getRequestURI(); + final String pathInfo = requestURI.substring((req.getContextPath() + req.getServletPath()).length()); + + LOGGER.trace("Processing request: {} SID: {}", requestURI, req.getSession(false) != null ? req.getSession().getId() : null); + + final Match match = this.container.getRegistry().findWebScript(req.getMethod(), URLDecoder.decode(pathInfo)); + if (match != null && match.getWebScript() != null) + { + final RequiredAuthentication reqAuth = match.getWebScript().getDescription().getRequiredAuthentication(); + if (RequiredAuthentication.none == reqAuth) + { + LOGGER.debug("Found webscript with no authentication - set NO_AUTH_REQUIRED flag."); + req.setAttribute(NO_AUTH_REQUIRED, Boolean.TRUE); + } + else if (RequiredAuthentication.guest == reqAuth && Boolean.parseBoolean(sreq.getParameter(ARG_GUEST))) + { + LOGGER.debug("Found webscript with guest authentication and request with set guest parameter - set NO_AUTH_REQUIRED flag."); + req.setAttribute(NO_AUTH_REQUIRED, Boolean.TRUE); + } + } + + chain.doFilter(sreq, sresp); + } + + /** + * + * {@inheritDoc} + */ + @Override + // ugh - Commons Logging - why does base class not have a sensible default?? + protected Log getLogger() + { + return LogFactory.getLog(this.getClass()); + } +} diff --git a/repository/src/main/java/de/acosix/alfresco/keycloak/repo/roles/RoleServiceImpl.java b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/roles/RoleServiceImpl.java index 36700b4..51b8c99 100644 --- a/repository/src/main/java/de/acosix/alfresco/keycloak/repo/roles/RoleServiceImpl.java +++ b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/roles/RoleServiceImpl.java @@ -312,7 +312,7 @@ public class RoleServiceImpl implements InitializingBean, RoleService } else { - LOGGER.debug("No role mapper defined for resource {}", roleNameMapper); + LOGGER.debug("No role mapper defined for resource {}", resourceName); roles = Collections.emptyList(); } } diff --git a/repository/src/main/webscripts/de/acosix/acosix-keycloak/roles.get.desc.xml b/repository/src/main/webscripts/de/acosix/keycloak/roles.get.desc.xml similarity index 100% rename from repository/src/main/webscripts/de/acosix/acosix-keycloak/roles.get.desc.xml rename to repository/src/main/webscripts/de/acosix/keycloak/roles.get.desc.xml diff --git a/repository/src/main/webscripts/de/acosix/acosix-keycloak/roles.get.json.ftl b/repository/src/main/webscripts/de/acosix/keycloak/roles.get.json.ftl similarity index 100% rename from repository/src/main/webscripts/de/acosix/acosix-keycloak/roles.get.json.ftl rename to repository/src/main/webscripts/de/acosix/keycloak/roles.get.json.ftl diff --git a/repository/src/test/docker/test-realm.json b/repository/src/test/docker/test-realm.json index 3143e3f..4abc0ee 100644 --- a/repository/src/test/docker/test-realm.json +++ b/repository/src/test/docker/test-realm.json @@ -1,1405 +1,165 @@ { "id": "test", "realm": "test", - "groups": [{ - "name": "Test A", - "subGroups": [{ - "name": "Test AA" - }, { - "name": "Test AB" - }] - }, { - "name": "Test B", - "subGroups": [{ - "name": "Test BA" - }] - }], - "users": [{ - "id": "service-account-alfresco", - "serviceAccountClientId": "alfresco", - "username": "service-account-alfresco", - "enabled": true, - "email": "service-account-alfresco@muster.com", - "realmRoles": [ - "offline_access", - "uma_authorization" - ], - "clientRoles": { - "account": [ - "view-profile", - "manage-account" - ], - "realm-management": [ - "view-users", - "view-clients" - ] - } - }, { - "id": "mmustermann", - "username": "mmustermann", - "enabled": true, - "email": "max.mustermann@muster.com", - "firstName": "Max", - "lastName": "Mustermann", - "credentials": [{ - "type": "password", - "value": "mmustermann" - }], - "realmRoles": [ - "user" - ], - "clientRoles": { - "account": [ - "view-profile", - "manage-account" - ] - }, - "groups": [ - "/Test A/Test AB", - "/Test B/Test BA" - ] - }, { - "id": "jdoe", - "username": "jdoe", - "enabled": true, - "email": "john.doe@muster.com", - "firstName": "John", - "lastName": "Doe", - "credentials": [{ - "type": "password", - "value": "jdoe" - }], - "realmRoles": [ - "user" - ], - "clientRoles": { - "account": [ - "view-profile", - "manage-account" - ] - } - }, { - "id": "ssuper", - "username": "ssuper", - "enabled": true, - "email": "suzy.super@muster.com", - "firstName": "Suzy", - "lastName": "Super", - "credentials": [{ - "type": "password", - "value": "ssuper" - }], - "realmRoles": [ - "user" - ], - "clientRoles": { - "account": [ - "view-profile", - "manage-account" - ], - "alfresco": [ - "admin" - ] - } - }], - "roles": { - "client": { - "alfresco": [{ - "id": "57944d14-7240-464b-925d-7778fa9b78e6", - "name": "admin", - "composite": false, - "clientRole": true, - "attributes": {} - }] - } - }, - "clients": [{ - "clientId": "alfresco", - "name": "Alfresco Repository", - "rootUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco", - "adminUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco/keycloak", - "baseUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco", - "surrogateAuthRequired": false, - "enabled": true, - "clientAuthenticatorType": "client-secret", - "secret": "6f70a28f-98cd-41ca-8f2f-368a8797d708", - "redirectUris": [ - "http://localhost:${docker.tests.repositoryPort}/alfresco/*" - ], - "webOrigins": [ - "http://localhost:${docker.tests.repositoryPort}" - ], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": true, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "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, - "protocolMappers": [{ - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-group-membership-mapper", - "consentRequired": false, - "config": { - "full.path": "true", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "groups", - "userinfo.token.claim": "true" - } - }], - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ], - "access": { - "view": true, - "configure": true, - "manage": true - } - }], - "notBefore": 0, - "revokeRefreshToken": false, - "refreshTokenMaxReuse": 0, - "accessTokenLifespan": 300, - "accessTokenLifespanForImplicitFlow": 900, - "ssoSessionIdleTimeout": 1800, - "ssoSessionMaxLifespan": 36000, - "ssoSessionIdleTimeoutRememberMe": 0, - "ssoSessionMaxLifespanRememberMe": 0, - "offlineSessionIdleTimeout": 2592000, - "offlineSessionMaxLifespanEnabled": false, - "offlineSessionMaxLifespan": 5184000, - "accessCodeLifespan": 60, - "accessCodeLifespanUserAction": 300, - "accessCodeLifespanLogin": 1800, - "actionTokenGeneratedByAdminLifespan": 43200, - "actionTokenGeneratedByUserLifespan": 300, "enabled": true, "sslRequired": "none", "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, - "defaultRoles": [ - "offline_access", - "uma_authorization" + "internationalizationEnabled": true, + "supportedLocales": [ + "en" ], - "requiredCredentials": [ - "password" - ], - "otpPolicyType": "totp", - "otpPolicyAlgorithm": "HmacSHA1", - "otpPolicyInitialCounter": 0, - "otpPolicyDigits": 6, - "otpPolicyLookAheadWindow": 1, - "otpPolicyPeriod": 30, - "otpSupportedApplications": [ - "FreeOTP", - "Google Authenticator" - ], - "scopeMappings": [{ - "clientScope": "offline_access", - "roles": [ - "offline_access" - ] - }], - "clientScopes": [{ - "id": "0ee41513-079a-4156-9eab-5709b18be2a6", - "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": "1218801d-c159-4ddd-901c-2fc5afa06170", - "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" - } - }] - }, + "defaultLocale": "en", + "clients": [ { - "id": "bac1ffb3-92bf-481d-b6f8-8dec9bbe7291", - "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": "4f28826f-46c6-4fe9-b499-611b66d9bc6f", - "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": "34521446-1260-416f-bbab-b13143cdf163", - "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": "7a6e0dc7-5a3b-4c0e-9a6c-48c08d62b3e8", - "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": "a69c70ca-70c0-465b-8faf-fffd427f90d9", - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "multivalued": "true", - "userinfo.token.claim": "true", - "user.attribute": "foo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "groups", - "jsonType.label": "String" - } - }, - { - "id": "5fadd383-2a4a-4970-a79e-9e9bc917476e", - "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": "3080e57a-c685-473d-977e-268f85e4d62d", - "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": "052c824f-caac-492c-9334-d68a1fe757e3", - "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": "850fe82e-ea0b-4cda-a0bc-dcc9d355c5a8", - "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": "63bf589d-e07e-4bae-b057-e7a7b8c72dc4", - "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": "d9c5f7c3-d075-4400-bf27-970df51c4217", - "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": "da5905e2-00ee-4ed0-ab7d-cdac7ead6206", - "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": "ae7cf419-6550-449c-9df1-0386bb0ee652", - "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": "ac275bed-9da2-4221-8b8b-f7b499cc2c4b", - "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": "3b88f7c9-62a1-42a2-b575-52181043e89c", - "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": "90145df4-77c3-4c7a-8e15-59434c46bea1", - "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": "5fea5786-6563-49c3-bdc1-26b125d5c8f0", - "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": "f802a038-2b1a-4642-8758-2923a5d67d76", - "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": "7d050eba-1d77-480c-a12c-674d9201d790", - "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": "6b54ca21-d615-4ef3-a703-0c0f20d9f393", - "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": "cd3664d6-1888-464f-b144-3d1d6f332956", - "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": "aafa8ba3-d0cd-4dd0-9238-73506a15b6b3", - "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": "52d6c5f9-d1cf-4dbd-a8f3-9ce438ee3868", - "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": "7dba042a-bb94-4307-a547-a02a0ab2239e", - "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": "a6fb8c23-cfb4-4a5f-afcf-1bd360959c6b", - "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": "3ddbd9c1-92f1-4717-870e-4492df1d463a", - "name": "role_list", - "description": "SAML role list", - "protocol": "saml", - "attributes": { - "consent.screen.text": "${samlRoleListScopeConsentText}", - "display.on.consent.screen": "true" - }, - "protocolMappers": [{ - "id": "51899037-a3df-4924-bd73-81f07cfb3aa9", - "name": "role list", - "protocol": "saml", - "protocolMapper": "saml-role-list-mapper", - "consentRequired": false, - "config": { - "single": "false", - "attribute.nameformat": "Basic", - "attribute.name": "Role" - } - }] - }, - { - "id": "4c15f94e-f490-4541-8c14-7b4734d6999b", - "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": "1908b63f-1be6-4f87-a947-30ee66721d05", - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": { - - } - }, - { - "id": "b830b103-f7af-4d78-8c44-53c6879544d6", - "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": "c3e6e3d7-e462-4e25-9a7c-99c5eee63194", - "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": "a6c18942-1bf9-4024-855e-65a5df06d810", - "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": "4652b835-1693-45ae-bad5-b61b534610de", - "name": "allowed web origins", - "protocol": "openid-connect", - "protocolMapper": "oidc-allowed-origins-mapper", - "consentRequired": false, - "config": { - - } - }] + "id": "alfresco", + "clientId": "alfresco", + "name": "Alfresco Repository", + "baseUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco", + "adminUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco/keycloak", + "redirectUris": [ + "http://localhost:${docker.tests.repositoryPort}/alfresco/*" + ], + "webOrigins": [ + "http://localhost:${docker.tests.repositoryPort}/alfresco" + ], + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "6f70a28f-98cd-41ca-8f2f-368a8797d708", + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "protocol": "openid-connect" } ], - "defaultDefaultClientScopes": [ - "role_list", - "roles", - "web-origins", - "email", - "profile" - ], - "defaultOptionalClientScopes": [ - "phone", - "address", - "offline_access", - "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" + "roles": { + "client": { + "alfresco": [ + { + "name": "admin", + "clientRole": true + } + ] + } }, - "smtpServer": { - - }, - "eventsEnabled": false, - "eventsListeners": [ - "jboss-logging" - ], - "enabledEventTypes": [], - "adminEventsEnabled": false, - "adminEventsDetailsEnabled": false, - "components": { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [{ - "id": "43a864c4-c4fa-4057-bf87-2ca409cde736", - "name": "Max Clients Limit", - "providerId": "max-clients", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - "max-clients": [ - "200" - ] - } - }, - { - "id": "6d4772af-f62e-40e9-8370-44aebf0d694d", - "name": "Consent Required", - "providerId": "consent-required", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - - } - }, - { - "id": "d474b02e-7d04-41c1-9c01-328221daa836", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "authenticated", - "subComponents": { - - }, - "config": { - "allow-default-scopes": [ - "true" - ] - } - }, - { - "id": "2f6ce962-4ad2-479b-87b2-35ea971039b1", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "authenticated", - "subComponents": { - - }, - "config": { - "allowed-protocol-mapper-types": [ - "oidc-address-mapper", - "oidc-sha256-pairwise-sub-mapper", - "oidc-usermodel-property-mapper", - "oidc-usermodel-attribute-mapper", - "saml-user-property-mapper", - "saml-user-attribute-mapper", - "saml-role-list-mapper", - "oidc-full-name-mapper" - ] - } - }, - { - "id": "3f7ae6b8-63c8-4ddf-82d8-afebf153a41a", - "name": "Full Scope Disabled", - "providerId": "scope", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - - } - }, - { - "id": "49326837-fe7d-47d6-85e7-5dd4028f0cd3", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - "allowed-protocol-mapper-types": [ - "oidc-usermodel-property-mapper", - "saml-role-list-mapper", - "oidc-sha256-pairwise-sub-mapper", - "oidc-full-name-mapper", - "saml-user-property-mapper", - "oidc-usermodel-attribute-mapper", - "oidc-address-mapper", - "saml-user-attribute-mapper" - ] - } - }, - { - "id": "c76f5e11-0576-4512-abf4-2d0b7cd5f355", - "name": "Trusted Hosts", - "providerId": "trusted-hosts", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - "host-sending-registration-request-must-match": [ - "true" - ], - "client-uris-must-match": [ - "true" - ] - } - }, - { - "id": "144efd74-bbbd-4176-8760-0e0819a61e5c", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - "allow-default-scopes": [ - "true" - ] - } - } - ], - "org.keycloak.keys.KeyProvider": [{ - "id": "005993b6-dcb3-4ebf-b19c-7287c740bb79", - "name": "rsa-generated", - "providerId": "rsa-generated", - "subComponents": { - - }, - "config": { - "priority": [ - "100" - ] - } - }, - { - "id": "865ea0f7-9411-4985-8516-a3a7112204f4", - "name": "aes-generated", - "providerId": "aes-generated", - "subComponents": { - - }, - "config": { - "priority": [ - "100" - ] - } - }, - { - "id": "7783eb59-57b1-491b-a570-934811ac95c3", - "name": "hmac-generated", - "providerId": "hmac-generated", - "subComponents": { - - }, - "config": { - "priority": [ - "100" - ], - "algorithm": [ - "HS256" - ] - } - } - ] - }, - "internationalizationEnabled": false, - "supportedLocales": [], - "authenticationFlows": [{ - "id": "50eda798-0ed6-4fd1-9071-977ca22b032f", - "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 + "groups": [ + { + "name": "Test A", + "subGroups": [ + { + "name": "Test AA" }, { - "authenticator": "idp-email-verification", - "requirement": "ALTERNATIVE", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "ALTERNATIVE", - "priority": 30, - "flowAlias": "Verify Existing Account by Re-authentication", - "userSetupAllowed": false, - "autheticatorFlow": true + "name": "Test AB" } ] }, { - "id": "49354897-5c61-4aca-8b08-0601202abf49", - "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 - }, + "name": "Test B", + "subGroups": [ { - "authenticator": "auth-otp-form", - "requirement": "OPTIONAL", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "name": "Test BA" } ] - }, - { - "id": "f23bad00-b78e-4262-a025-5b2ef1d09dc4", - "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": "15d11f2c-9f51-4e41-8ca7-020b7b9e9335", - "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": "6846e2ce-b014-4296-a111-6f68ca10c985", - "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 - }, - { - "authenticator": "direct-grant-validate-otp", - "requirement": "OPTIONAL", - "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "9425e1d1-4533-413d-83c5-38c9657a355f", - "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": "eb15d55b-a601-493c-9f49-069695624ada", - "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 - }, - { - "authenticatorConfig": "create unique user config", - "authenticator": "idp-create-user-if-unique", - "requirement": "ALTERNATIVE", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "ALTERNATIVE", - "priority": 30, - "flowAlias": "Handle Existing Account", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "4fa685ea-65dd-4019-b3a3-a5f95b36e9f4", - "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 - }, - { - "authenticator": "auth-otp-form", - "requirement": "OPTIONAL", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "8edbb281-f132-4625-bf15-ebc314dd0c5d", - "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 - }, - { - "authenticator": "basic-auth", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "basic-auth-otp", - "requirement": "DISABLED", - "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "auth-spnego", - "requirement": "DISABLED", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "88374fbb-95fa-4bd5-940a-1289a9a051f6", - "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": "088ede2e-2dce-466d-b25f-62cc07c12bee", - "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": "065e575d-20fe-45e1-ab7d-d54ef056db8e", - "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 - }, - { - "authenticator": "reset-otp", - "requirement": "OPTIONAL", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "e1f9c5ba-5e45-4c51-a3cb-c10303b8c02e", - "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": "1593e111-7e5e-4ee2-b33d-f459834e4e3b", - "alias": "create unique user config", - "config": { - "require.password.update.after.registration": "false" + "users": [ + { + "id": "service-account-alfresco", + "serviceAccountClientId": "alfresco", + "username": "service-account-alfresco", + "enabled": true, + "email": "service-account-alfresco@muster.com", + "realmRoles": [ + "offline_access", + "uma_authorization" + ], + "clientRoles": { + "account": [ + "view-profile", + "manage-account" + ], + "realm-management": [ + "view-users", + "view-clients" + ] } }, { - "id": "ae5f6b14-fb84-4320-90a4-da8c80c379bf", - "alias": "review profile config", - "config": { - "update.profile.on.first.login": "missing" + "id": "mmustermann", + "username": "mmustermann", + "enabled": true, + "email": "max.mustermann@muster.com", + "firstName": "Max", + "lastName": "Mustermann", + "credentials": [ + { + "type": "password", + "value": "mmustermann" + } + ], + "realmRoles": [ + "user" + ], + "clientRoles": { + "account": [ + "view-profile", + "manage-account" + ] + }, + "groups": [ + "/Test A/Test AB", + "/Test B/Test BA" + ] + }, + { + "id": "jdoe", + "username": "jdoe", + "enabled": true, + "email": "john.doe@muster.com", + "firstName": "John", + "lastName": "Doe", + "credentials": [ + { + "type": "password", + "value": "jdoe" + } + ], + "realmRoles": [ + "user" + ], + "clientRoles": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + { + "id": "ssuper", + "username": "ssuper", + "enabled": true, + "email": "suzy.super@muster.com", + "firstName": "Suzy", + "lastName": "Super", + "credentials": [ + { + "type": "password", + "value": "ssuper" + } + ], + "realmRoles": [ + "user" + ], + "clientRoles": { + "account": [ + "view-profile", + "manage-account" + ], + "alfresco": [ + "admin" + ] } } - ], - "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": { - - } - } - ], - "browserFlow": "browser", - "registrationFlow": "registration", - "directGrantFlow": "direct grant", - "resetCredentialsFlow": "reset credentials", - "clientAuthenticationFlow": "clients", - "dockerAuthenticationFlow": "docker auth", - "attributes": { - "_browser_header.xXSSProtection": "1; mode=block", - "_browser_header.xFrameOptions": "SAMEORIGIN", - "_browser_header.strictTransportSecurity": "max-age=31536000; includeSubDomains", - "permanentLockout": "false", - "quickLoginCheckMilliSeconds": "1000", - "_browser_header.xRobotsTag": "none", - "maxFailureWaitSeconds": "900", - "minimumQuickLoginWaitSeconds": "60", - "failureFactor": "30", - "actionTokenGeneratedByUserLifespan": "300", - "maxDeltaTimeSeconds": "43200", - "_browser_header.xContentTypeOptions": "nosniff", - "offlineSessionMaxLifespan": "5184000", - "actionTokenGeneratedByAdminLifespan": "43200", - "_browser_header.contentSecurityPolicyReportOnly": "", - "bruteForceProtected": "false", - "_browser_header.contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "waitIncrementSeconds": "60", - "offlineSessionMaxLifespanEnabled": "false" - }, - "keycloakVersion": "6.0.1", - "userManagedAccessAllowed": false + ] } \ No newline at end of file diff --git a/share-dependencies/pom.xml b/share-dependencies/pom.xml index 55519a5..b5ce84b 100644 --- a/share-dependencies/pom.xml +++ b/share-dependencies/pom.xml @@ -26,19 +26,20 @@ de.acosix.alfresco.keycloak.share.deps Acosix Alfresco Keycloak - Share Dependencies Module - Aggregate (Uber-)JAR of all dependencies for the Acosix Alfresco Keycloak Share Module + Aggregate (Uber-)JAR of all dependencies for the Acosix Alfresco Keycloak Share Module (except BouncyCastle) org.keycloak keycloak-adapter-core + - org.bouncycastle + com.sun.activation * - com.fasterxml.jackson.core + org.bouncycastle * @@ -48,13 +49,19 @@ org.keycloak keycloak-servlet-adapter-spi + + + com.sun.activation + * + org.bouncycastle * + - com.fasterxml.jackson.core - * + org.apache.httpcomponents + httpcomponents-client @@ -63,12 +70,13 @@ org.keycloak keycloak-servlet-filter-adapter + - org.bouncycastle + com.sun.activation * - com.fasterxml.jackson.core + org.bouncycastle * @@ -77,6 +85,12 @@ org.keycloak keycloak-authz-client + + + org.bouncycastle + * + + @@ -97,6 +111,10 @@ org.keycloak de.acosix.alfresco.keycloak.share.deps.keycloak + + com.fasterxml.jackson + de.acosix.alfresco.keycloak.share.deps.jackson + org.jboss.logging de.acosix.alfresco.keycloak.share.deps.jboss.logging diff --git a/share/pom.xml b/share/pom.xml index 71f5d58..150b686 100644 --- a/share/pom.xml +++ b/share/pom.xml @@ -27,6 +27,10 @@ de.acosix.alfresco.keycloak.share Acosix Alfresco Keycloak - Share Module + + 8380 + + @@ -38,6 +42,12 @@ test + + org.bouncycastle + bcpkix-jdk15on + 1.60 + + @@ -55,23 +65,21 @@ - org.keycloak - keycloak-adapter-core + ${project.groupId} + de.acosix.alfresco.keycloak.share.deps + ${project.version} + + + org.keycloak + * + + - + + - org.keycloak - keycloak-servlet-adapter-spi - - - - org.keycloak - keycloak-servlet-filter-adapter - - - - org.keycloak - keycloak-authz-client + org.bouncycastle + bcpkix-jdk15on @@ -109,6 +117,16 @@ installable + + org.orderofthebee.support-tools + support-tools-repo + + + + org.orderofthebee.support-tools + support-tools-share + + junit junit @@ -163,7 +181,13 @@ - + + + + ${project.build.directory}/docker/share-logs:/usr/local/tomcat/logs + + + diff --git a/share/src/main/assembly/amp.xml b/share/src/main/assembly/amp.xml index a4a92a2..f099c97 100644 --- a/share/src/main/assembly/amp.xml +++ b/share/src/main/assembly/amp.xml @@ -45,10 +45,8 @@ lib - org.keycloak:* - org.jboss.logging:* org.bouncycastle:* - com.fasterxml.jackson.core:* + ${project.groupId}:${project.artifactId}.deps:* diff --git a/share/src/main/config/default-config.xml b/share/src/main/config/default-config.xml index d89601b..131691c 100644 --- a/share/src/main/config/default-config.xml +++ b/share/src/main/config/default-config.xml @@ -25,7 +25,7 @@ - + true @@ -50,7 +50,7 @@ - + 60000 diff --git a/share/src/main/config/log4j.properties b/share/src/main/config/log4j.properties index 18249c2..a38a08d 100644 --- a/share/src/main/config/log4j.properties +++ b/share/src/main/config/log4j.properties @@ -1 +1,5 @@ -log4j.logger.${project.artifactId}=INFO \ No newline at end of file +log4j.logger.${project.artifactId}=INFO +log4j.logger.${project.artifactId}.deps=ERROR +log4j.logger.${project.artifactId}.deps.keycloak=ERROR +log4j.logger.${project.artifactId}.deps.jackson=ERROR +log4j.logger.${project.artifactId}.deps.jboss=ERROR \ No newline at end of file diff --git a/share/src/main/globalConfig/site-data/extensions/acosix-keycloak-extension.xml b/share/src/main/globalConfig/site-data/extensions/acosix-keycloak-extension.xml index fd423ab..2b99acf 100644 --- a/share/src/main/globalConfig/site-data/extensions/acosix-keycloak-extension.xml +++ b/share/src/main/globalConfig/site-data/extensions/acosix-keycloak-extension.xml @@ -27,15 +27,15 @@ org.alfresco de.acosix.keycloak.customisations - - - org.alfresco.share.pages - de.acosix.keycloak.customisations.share.header - - share-header - - + + org.alfresco.share.pages + de.acosix.keycloak.customisations.share.header + + share-header + + + diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigElement.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigElement.java index ac258ea..ba3016a 100644 --- a/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigElement.java +++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigElement.java @@ -31,13 +31,12 @@ import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.util.EqualsHelper; import org.alfresco.util.ParameterCheck; -import org.keycloak.representations.adapters.config.AdapterConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.extensions.config.ConfigElement; -import com.fasterxml.jackson.annotation.JsonProperty; - +import de.acosix.alfresco.keycloak.share.deps.jackson.annotation.JsonProperty; +import de.acosix.alfresco.keycloak.share.deps.keycloak.representations.adapters.config.AdapterConfig; import de.acosix.alfresco.utility.share.config.BaseCustomConfigElement; import de.acosix.alfresco.utility.share.config.ConfigValueHolder; @@ -137,6 +136,8 @@ public class KeycloakAdapterConfigElement extends BaseCustomConfigElement protected final ConfigValueHolder socketTimeout = new ConfigValueHolder<>(); + protected final ConfigValueHolder directAuthHost = new ConfigValueHolder<>(); + /** * Creates a new instance of this class. */ @@ -179,6 +180,23 @@ public class KeycloakAdapterConfigElement extends BaseCustomConfigElement this.socketTimeout.setValue(socketTimeout); } + /** + * @return the directAuthHost + */ + public String getDirectAuthHost() + { + return this.directAuthHost.getValue(); + } + + /** + * @param directAuthHost + * the directAuthHost to set + */ + public void setDirectAuthHost(final String directAuthHost) + { + this.directAuthHost.setValue(directAuthHost); + } + /** * Checks if a specific field is supported by this config element. * @@ -386,6 +404,16 @@ public class KeycloakAdapterConfigElement extends BaseCustomConfigElement otherConfigElement.getSocketTimeout() != null ? otherConfigElement.getSocketTimeout() : this.getSocketTimeout()); } + if (otherConfigElement.directAuthHost.isUnset()) + { + combined.directAuthHost.unset(); + } + else + { + combined.setDirectAuthHost( + otherConfigElement.getDirectAuthHost() != null ? otherConfigElement.getDirectAuthHost() : this.getDirectAuthHost()); + } + return combined; } @@ -401,16 +429,12 @@ public class KeycloakAdapterConfigElement extends BaseCustomConfigElement builder.append(this.configValueByField); builder.append(",markedAsUnset="); builder.append(this.markedAsUnset); - if (this.connectionTimeout != null) - { - builder.append(",connectionTimeout="); - builder.append(this.connectionTimeout); - } - if (this.connectionTimeout != null) - { - builder.append(",socketTimeout="); - builder.append(this.socketTimeout); - } + builder.append(",connectionTimeout="); + builder.append(this.connectionTimeout); + builder.append(",socketTimeout="); + builder.append(this.socketTimeout); + builder.append(",directAuthHost="); + builder.append(this.directAuthHost); builder.append("]"); return builder.toString(); } @@ -432,8 +456,9 @@ public class KeycloakAdapterConfigElement extends BaseCustomConfigElement result = prime * result + valueHash; } - result = prime * result + (this.connectionTimeout != null ? this.connectionTimeout.hashCode() : 0); - result = prime * result + (this.socketTimeout != null ? this.socketTimeout.hashCode() : 0); + result = prime * result + this.connectionTimeout.hashCode(); + result = prime * result + this.socketTimeout.hashCode(); + result = prime * result + this.directAuthHost.hashCode(); return result; } diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigElementReader.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigElementReader.java index bbc3f03..247693e 100644 --- a/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigElementReader.java +++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigElementReader.java @@ -129,6 +129,10 @@ public class KeycloakAdapterConfigElementReader implements ConfigElementReader final String prospectiveSocketTimeout = subElement.getTextTrim(); configElement.setSocketTimeout(prospectiveSocketTimeout.isEmpty() ? null : Long.valueOf(prospectiveSocketTimeout)); break; + case "directAuthHost": + final String prospectiveDirectAuthHost = subElement.getTextTrim(); + configElement.setDirectAuthHost(prospectiveDirectAuthHost.isEmpty() ? null : prospectiveDirectAuthHost); + break; default: LOGGER.warn("Encountered unsupported Keycloak Adapter config element {}", subElementName); } diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/spring/KeycloakAuthenticationFilterActivation.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/spring/KeycloakAuthenticationFilterActivation.java index 9aa6fd3..31703a8 100644 --- a/share/src/main/java/de/acosix/alfresco/keycloak/share/spring/KeycloakAuthenticationFilterActivation.java +++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/spring/KeycloakAuthenticationFilterActivation.java @@ -78,6 +78,8 @@ public class KeycloakAuthenticationFilterActivation implements BeanDefinitionReg if (registry.containsBeanDefinition(keycloakFilterBeanName)) { + LOGGER.debug("Activating KeycloakAuthenticationFilter bean"); + // re-register default filter under different name final BeanDefinition defaultSsoAuthenticationFilter = registry.getBeanDefinition(DEFAULT_SSO_AUTHENTICATION_FILTER_NAME); registry.removeBeanDefinition(DEFAULT_SSO_AUTHENTICATION_FILTER_NAME); @@ -92,6 +94,8 @@ public class KeycloakAuthenticationFilterActivation implements BeanDefinitionReg keycloakSsoAuthenticationFilter.getPropertyValues().add("defaultSsoFilter", new RuntimeBeanReference(defaultSsoAuthenticationFilterReplacementName)); registry.registerBeanDefinition(DEFAULT_SSO_AUTHENTICATION_FILTER_NAME, keycloakSsoAuthenticationFilter); + + LOGGER.debug("Activated KeycloakAuthenticationFilter bean"); } else { diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/DefaultSessionIdMapper.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/DefaultSessionIdMapper.java index 742ffdc..9391310 100644 --- a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/DefaultSessionIdMapper.java +++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/DefaultSessionIdMapper.java @@ -25,14 +25,14 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.keycloak.adapters.spi.InMemorySessionIdMapper; -import org.keycloak.adapters.spi.SessionIdMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.extensions.config.ConfigService; import de.acosix.alfresco.keycloak.share.config.KeycloakAuthenticationConfigElement; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.spi.InMemorySessionIdMapper; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.spi.SessionIdMapper; /** * This implementation of a {@link SessionIdMapper Keycloak session ID mapper} is based on the {@link InMemorySessionIdMapper in-memory diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java index ef920c4..909df8c 100644 --- a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java +++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java @@ -16,6 +16,7 @@ package de.acosix.alfresco.keycloak.share.web; import java.io.IOException; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -38,25 +39,12 @@ import javax.servlet.http.HttpSession; import org.alfresco.util.PropertyCheck; import org.alfresco.web.site.servlet.SSOAuthenticationFilter; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.AdapterDeploymentContext; -import org.keycloak.adapters.AuthenticatedActionsHandler; -import org.keycloak.adapters.HttpClientBuilder; -import org.keycloak.adapters.KeycloakDeployment; -import org.keycloak.adapters.KeycloakDeploymentBuilder; -import org.keycloak.adapters.OAuthRequestAuthenticator; -import org.keycloak.adapters.OidcKeycloakAccount; -import org.keycloak.adapters.PreAuthActionsHandler; -import org.keycloak.adapters.servlet.FilterRequestAuthenticator; -import org.keycloak.adapters.servlet.OIDCFilterSessionStore; -import org.keycloak.adapters.servlet.OIDCServletHttpFacade; -import org.keycloak.adapters.spi.AuthOutcome; -import org.keycloak.adapters.spi.AuthenticationError; -import org.keycloak.adapters.spi.KeycloakAccount; -import org.keycloak.adapters.spi.SessionIdMapper; -import org.keycloak.adapters.spi.UserSessionManagement; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.adapters.config.AdapterConfig; +import org.apache.http.HttpHost; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.params.ConnRoutePNames; +import org.apache.http.conn.params.ConnRouteParams; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.params.HttpParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; @@ -83,6 +71,25 @@ import org.springframework.extensions.webscripts.servlet.DependencyInjectedFilte import de.acosix.alfresco.keycloak.share.config.KeycloakAdapterConfigElement; import de.acosix.alfresco.keycloak.share.config.KeycloakAuthenticationConfigElement; import de.acosix.alfresco.keycloak.share.config.KeycloakConfigConstants; +import de.acosix.alfresco.keycloak.share.deps.keycloak.KeycloakSecurityContext; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.AdapterDeploymentContext; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.AuthenticatedActionsHandler; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.HttpClientBuilder; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.KeycloakDeployment; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.KeycloakDeploymentBuilder; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.OAuthRequestAuthenticator; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.OidcKeycloakAccount; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.PreAuthActionsHandler; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.servlet.FilterRequestAuthenticator; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.servlet.OIDCFilterSessionStore; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.servlet.OIDCServletHttpFacade; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.spi.AuthOutcome; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.spi.AuthenticationError; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.spi.KeycloakAccount; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.spi.SessionIdMapper; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.spi.UserSessionManagement; +import de.acosix.alfresco.keycloak.share.deps.keycloak.representations.AccessToken; +import de.acosix.alfresco.keycloak.share.deps.keycloak.representations.adapters.config.AdapterConfig; import de.acosix.alfresco.keycloak.share.remote.BearerTokenAwareSlingshotAlfrescoConnector; /** @@ -259,7 +266,10 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I { httpClientBuilder = httpClientBuilder.socketTimeout(socketTimeout.longValue(), TimeUnit.MILLISECONDS); } - this.keycloakDeployment.setClient(httpClientBuilder.build(adapterConfiguration)); + + final HttpClient client = httpClientBuilder.build(adapterConfiguration); + this.configureForcedRouteIfNecessary(keycloakAdapterConfig, client); + this.keycloakDeployment.setClient(client); } this.deploymentContext = new AdapterDeploymentContext(this.keycloakDeployment); @@ -516,7 +526,6 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I } else { - if (authOutcome == AuthOutcome.NOT_ATTEMPTED) { LOGGER.debug("No authentication took place - continueing with filter chain processing"); @@ -1129,4 +1138,29 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I }); } } + + @SuppressWarnings("deprecation") + protected void configureForcedRouteIfNecessary(final KeycloakAdapterConfigElement configElement, final HttpClient client) + { + final String directAuthHost = configElement.getDirectAuthHost(); + if (directAuthHost != null && !directAuthHost.isEmpty()) + { + final HttpHost host = HttpHost.create(directAuthHost); + final HttpParams params = client.getParams(); + final InetAddress local = ConnRouteParams.getLocalAddress(params); + final HttpHost proxy = ConnRouteParams.getDefaultProxy(params); + final boolean secure = host.getSchemeName().equalsIgnoreCase("https"); + + HttpRoute route; + if (proxy == null) + { + route = new HttpRoute(host, local, secure); + } + else + { + route = new HttpRoute(host, local, proxy, secure); + } + params.setParameter(ConnRoutePNames.FORCED_ROUTE, route); + } + } } diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/ResponseHeaderCookieCaptureServletHttpFacade.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/ResponseHeaderCookieCaptureServletHttpFacade.java index 87c7195..8c53404 100644 --- a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/ResponseHeaderCookieCaptureServletHttpFacade.java +++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/ResponseHeaderCookieCaptureServletHttpFacade.java @@ -26,8 +26,9 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.alfresco.util.Pair; -import org.keycloak.adapters.servlet.ServletHttpFacade; -import org.keycloak.adapters.spi.HttpFacade; + +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.servlet.ServletHttpFacade; +import de.acosix.alfresco.keycloak.share.deps.keycloak.adapters.spi.HttpFacade; /** * This {@link HttpFacade} wraps servlet requests and responses in such a way that any response headers / cookies being set by Keycloak diff --git a/share/src/test/docker/alfresco/extension/alfresco-global.addition.properties b/share/src/test/docker/alfresco/extension/alfresco-global.addition.properties index 12f06d8..795bafd 100644 --- a/share/src/test/docker/alfresco/extension/alfresco-global.addition.properties +++ b/share/src/test/docker/alfresco/extension/alfresco-global.addition.properties @@ -24,5 +24,8 @@ keycloak.adapter.resource=alfresco keycloak.adapter.credentials.provider=secret keycloak.adapter.credentials.secret=6f70a28f-98cd-41ca-8f2f-368a8797d708 +# localhost in auth-server-url won't work for direct access in a Docker deployment +keycloak.authentication.directAuthHost=http://host.docker.internal:8380 + keycloak.synchronization.userFilter.containedInGroup.property.groupPaths=/Test A keycloak.synchronization.groupFilter.containedInGroup.property.groupPaths=/Test A diff --git a/share/src/test/docker/alfresco/web-extension/dev-log4j.properties b/share/src/test/docker/alfresco/web-extension/dev-log4j.properties new file mode 100644 index 0000000..9018760 --- /dev/null +++ b/share/src/test/docker/alfresco/web-extension/dev-log4j.properties @@ -0,0 +1,25 @@ +# +# Copyright 2019 - 2020 Acosix GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +log4j.rootLogger=error, File + +log4j.appender.File=org.apache.log4j.DailyRollingFileAppender +log4j.appender.File.File=\${catalina.base}/logs/share.log +log4j.appender.File.Append=true +log4j.appender.File.DatePattern='.'yyyy-MM-dd +log4j.appender.File.layout=org.apache.log4j.PatternLayout +log4j.appender.File.layout.ConversionPattern=%d{yyyy-MM-dd} %d{ABSOLUTE} %-5p [%c] [%t] %m%n + +log4j.logger.${project.artifactId}=DEBUG \ No newline at end of file diff --git a/share/src/test/docker/alfresco/web-extension/share-config-custom.xml b/share/src/test/docker/alfresco/web-extension/share-config-custom.xml index 1a76d9b..4570606 100644 --- a/share/src/test/docker/alfresco/web-extension/share-config-custom.xml +++ b/share/src/test/docker/alfresco/web-extension/share-config-custom.xml @@ -16,13 +16,76 @@ --> - + + + + alfrescoCookie + Alfresco Connector + Connects to an Alfresco instance using cookie-based authentication + de.acosix.alfresco.keycloak.share.remote.BearerTokenAwareSlingshotAlfrescoConnector + + + + alfrescoHeader + Alfresco Connector + Connects to an Alfresco instance using header and cookie-based authentication + de.acosix.alfresco.keycloak.share.remote.BearerTokenAwareSlingshotAlfrescoConnector + SsoUserHeader + + + + alfresco + Alfresco - user access + Access to Alfresco Repository WebScripts that require user authentication + alfrescoCookie + http://repository:8080/alfresco/wcs + user + true + + + + alfresco-feed + Alfresco Feed + Alfresco Feed - supports basic HTTP authentication via the EndPointProxyServlet + alfrescoHeader + http://repository:8080/alfresco/wcs + true + user + true + + + + alfresco-api + alfresco + Alfresco Public API - user access + Access to Alfresco Repository Public API that require user authentication. + This makes use of the authentication that is provided by parent 'alfresco' endpoint. + + alfrescoHeader + http://repository:8080/alfresco/api + user + true + + + + + + + true + true + false + + http://host.docker.internal:8380 + http://${docker.tests.host.name}:${docker.tests.keycloakPort}/auth + test + alfresco-share + none + false - secret - test + secret + a5b3e8bc-39cc-4ddd-8c8f-1c34e7a35975 - true diff --git a/share/src/test/docker/repository-it.xml b/share/src/test/docker/repository-it.xml index 817cda1..1d203a3 100644 --- a/share/src/test/docker/repository-it.xml +++ b/share/src/test/docker/repository-it.xml @@ -59,10 +59,16 @@ WEB-INF/lib - ${project.groupId}:de.acosix.alfresco.keycloak.repo.deps:* + + + + com.cronutils:* + net.time4j:* + org.orderofthebee.support-tools:support-tools-repo:* de.acosix.alfresco.utility:de.acosix.alfresco.utility.common:* de.acosix.alfresco.utility:de.acosix.alfresco.utility.core.repo.quartz1:* de.acosix.alfresco.utility:de.acosix.alfresco.utility.core.repo.quartz2:* + ${project.groupId}:de.acosix.alfresco.keycloak.repo.deps:* de.acosix.alfresco.utility:de.acosix.alfresco.utility.core.repo:jar:installable:* ${project.groupId}:de.acosix.alfresco.keycloak.repo:jar:installable:* diff --git a/share/src/test/docker/share-it.xml b/share/src/test/docker/share-it.xml index 29fa83a..32dd0f1 100644 --- a/share/src/test/docker/share-it.xml +++ b/share/src/test/docker/share-it.xml @@ -23,13 +23,6 @@ dir false - - - ${project.basedir}/src/test/docker/share-log4j.properties - WEB-INF/classes - log4j.properties - - ${project.build.directory} @@ -74,12 +67,14 @@ WEB-INF/lib ${project.groupId}:de.acosix.alfresco.keycloak.share.deps:* + org.bouncycastle:* compile WEB-INF/lib + org.orderofthebee.support-tools:support-tools-share:* de.acosix.alfresco.utility:de.acosix.alfresco.utility.common:* de.acosix.alfresco.utility:de.acosix.alfresco.utility.core.share:jar:installable:* diff --git a/share/src/test/docker/share-logs/dummy.properties b/share/src/test/docker/share-logs/dummy.properties new file mode 100644 index 0000000..5d13f33 --- /dev/null +++ b/share/src/test/docker/share-logs/dummy.properties @@ -0,0 +1 @@ +# only exists to ensure Maven creates path in project ./target \ No newline at end of file diff --git a/share/src/test/docker/test-realm.json b/share/src/test/docker/test-realm.json index 6a68685..a1c3221 100644 --- a/share/src/test/docker/test-realm.json +++ b/share/src/test/docker/test-realm.json @@ -1,1404 +1,182 @@ { "id": "test", "realm": "test", - "groups": [{ - "name": "Test A", - "subGroups": [{ - "name": "Test AA" - }, { - "name": "Test AB" - }] - }, { - "name": "Test B", - "subGroups": [{ - "name": "Test BA" - }] - }], - "users": [{ - "id": "service-account-alfresco", - "serviceAccountClientId": "alfresco", - "username": "service-account-alfresco", - "enabled": true, - "email": "service-account-alfresco@muster.com", - "realmRoles": [ - "offline_access", - "uma_authorization" - ], - "clientRoles": { - "account": [ - "view-profile", - "manage-account" - ], - "realm-management": [ - "view-users" - ] - } - }, { - "id": "mmustermann", - "username": "mmustermann", - "enabled": true, - "email": "max.mustermann@muster.com", - "firstName": "Max", - "lastName": "Mustermann", - "credentials": [{ - "type": "password", - "value": "mmustermann" - }], - "realmRoles": [ - "user" - ], - "clientRoles": { - "account": [ - "view-profile", - "manage-account" - ] - }, - "groups": [ - "/Test A/Test AB", - "/Test B/Test BA" - ] - }, { - "id": "jdoe", - "username": "jdoe", - "enabled": true, - "email": "john.doe@muster.com", - "firstName": "John", - "lastName": "Doe", - "credentials": [{ - "type": "password", - "value": "jdoe" - }], - "realmRoles": [ - "user" - ], - "clientRoles": { - "account": [ - "view-profile", - "manage-account" - ] - } - }, { - "id": "ssuper", - "username": "ssuper", - "enabled": true, - "email": "suzy.super@muster.com", - "firstName": "Suzy", - "lastName": "Super", - "credentials": [{ - "type": "password", - "value": "ssuper" - }], - "realmRoles": [ - "user" - ], - "clientRoles": { - "account": [ - "view-profile", - "manage-account" - ], - "alfresco": [ - "admin" - ] - } - }], - "roles": { - "client": { - "alfresco": [{ - "id": "57944d14-7240-464b-925d-7778fa9b78e6", - "name": "admin", - "composite": false, - "clientRole": true, - "attributes": {} - }] - } - }, - "clients": [{ - "clientId": "alfresco", - "name": "Alfresco Repository", - "rootUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco", - "adminUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco/keycloak", - "baseUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco", - "surrogateAuthRequired": false, - "enabled": true, - "clientAuthenticatorType": "client-secret", - "secret": "6f70a28f-98cd-41ca-8f2f-368a8797d708", - "redirectUris": [ - "http://localhost:${docker.tests.repositoryPort}/alfresco/*" - ], - "webOrigins": [ - "http://localhost:${docker.tests.repositoryPort}" - ], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": true, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "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, - "protocolMappers": [{ - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-group-membership-mapper", - "consentRequired": false, - "config": { - "full.path": "true", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "groups", - "userinfo.token.claim": "true" - } - }], - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ], - "access": { - "view": true, - "configure": true, - "manage": true - } - }], - "notBefore": 0, - "revokeRefreshToken": false, - "refreshTokenMaxReuse": 0, - "accessTokenLifespan": 300, - "accessTokenLifespanForImplicitFlow": 900, - "ssoSessionIdleTimeout": 1800, - "ssoSessionMaxLifespan": 36000, - "ssoSessionIdleTimeoutRememberMe": 0, - "ssoSessionMaxLifespanRememberMe": 0, - "offlineSessionIdleTimeout": 2592000, - "offlineSessionMaxLifespanEnabled": false, - "offlineSessionMaxLifespan": 5184000, - "accessCodeLifespan": 60, - "accessCodeLifespanUserAction": 300, - "accessCodeLifespanLogin": 1800, - "actionTokenGeneratedByAdminLifespan": 43200, - "actionTokenGeneratedByUserLifespan": 300, "enabled": true, "sslRequired": "none", "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, - "defaultRoles": [ - "offline_access", - "uma_authorization" + "internationalizationEnabled": true, + "supportedLocales": [ + "en" ], - "requiredCredentials": [ - "password" - ], - "otpPolicyType": "totp", - "otpPolicyAlgorithm": "HmacSHA1", - "otpPolicyInitialCounter": 0, - "otpPolicyDigits": 6, - "otpPolicyLookAheadWindow": 1, - "otpPolicyPeriod": 30, - "otpSupportedApplications": [ - "FreeOTP", - "Google Authenticator" - ], - "scopeMappings": [{ - "clientScope": "offline_access", - "roles": [ - "offline_access" - ] - }], - "clientScopes": [{ - "id": "0ee41513-079a-4156-9eab-5709b18be2a6", - "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": "1218801d-c159-4ddd-901c-2fc5afa06170", - "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" - } - }] - }, + "defaultLocale": "en", + "clients": [ { - "id": "bac1ffb3-92bf-481d-b6f8-8dec9bbe7291", - "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": "4f28826f-46c6-4fe9-b499-611b66d9bc6f", - "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": "34521446-1260-416f-bbab-b13143cdf163", - "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": "7a6e0dc7-5a3b-4c0e-9a6c-48c08d62b3e8", - "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": "a69c70ca-70c0-465b-8faf-fffd427f90d9", - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "multivalued": "true", - "userinfo.token.claim": "true", - "user.attribute": "foo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "groups", - "jsonType.label": "String" - } - }, - { - "id": "5fadd383-2a4a-4970-a79e-9e9bc917476e", - "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": "3080e57a-c685-473d-977e-268f85e4d62d", - "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": "052c824f-caac-492c-9334-d68a1fe757e3", - "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": "850fe82e-ea0b-4cda-a0bc-dcc9d355c5a8", - "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": "63bf589d-e07e-4bae-b057-e7a7b8c72dc4", - "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": "d9c5f7c3-d075-4400-bf27-970df51c4217", - "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": "da5905e2-00ee-4ed0-ab7d-cdac7ead6206", - "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": "ae7cf419-6550-449c-9df1-0386bb0ee652", - "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": "ac275bed-9da2-4221-8b8b-f7b499cc2c4b", - "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": "3b88f7c9-62a1-42a2-b575-52181043e89c", - "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": "90145df4-77c3-4c7a-8e15-59434c46bea1", - "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": "5fea5786-6563-49c3-bdc1-26b125d5c8f0", - "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": "f802a038-2b1a-4642-8758-2923a5d67d76", - "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": "7d050eba-1d77-480c-a12c-674d9201d790", - "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": "6b54ca21-d615-4ef3-a703-0c0f20d9f393", - "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": "cd3664d6-1888-464f-b144-3d1d6f332956", - "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": "aafa8ba3-d0cd-4dd0-9238-73506a15b6b3", - "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": "52d6c5f9-d1cf-4dbd-a8f3-9ce438ee3868", - "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": "7dba042a-bb94-4307-a547-a02a0ab2239e", - "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": "a6fb8c23-cfb4-4a5f-afcf-1bd360959c6b", - "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": "3ddbd9c1-92f1-4717-870e-4492df1d463a", - "name": "role_list", - "description": "SAML role list", - "protocol": "saml", - "attributes": { - "consent.screen.text": "${samlRoleListScopeConsentText}", - "display.on.consent.screen": "true" - }, - "protocolMappers": [{ - "id": "51899037-a3df-4924-bd73-81f07cfb3aa9", - "name": "role list", - "protocol": "saml", - "protocolMapper": "saml-role-list-mapper", - "consentRequired": false, - "config": { - "single": "false", - "attribute.nameformat": "Basic", - "attribute.name": "Role" - } - }] - }, - { - "id": "4c15f94e-f490-4541-8c14-7b4734d6999b", - "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": "1908b63f-1be6-4f87-a947-30ee66721d05", - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": { - - } - }, - { - "id": "b830b103-f7af-4d78-8c44-53c6879544d6", - "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": "c3e6e3d7-e462-4e25-9a7c-99c5eee63194", - "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": "a6c18942-1bf9-4024-855e-65a5df06d810", - "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": "4652b835-1693-45ae-bad5-b61b534610de", - "name": "allowed web origins", - "protocol": "openid-connect", - "protocolMapper": "oidc-allowed-origins-mapper", - "consentRequired": false, - "config": { - - } - }] + "id": "alfresco", + "clientId": "alfresco", + "name": "Alfresco Repository", + "baseUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco", + "adminUrl": "http://localhost:${docker.tests.repositoryPort}/alfresco/keycloak", + "redirectUris": [ + "http://localhost:${docker.tests.repositoryPort}/alfresco/*" + ], + "webOrigins": [ + "http://localhost:${docker.tests.repositoryPort}/alfresco" + ], + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "6f70a28f-98cd-41ca-8f2f-368a8797d708", + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "protocol": "openid-connect" + }, { + "id": "alfresco-share", + "clientId": "alfresco-share", + "name": "Alfresco Share", + "baseUrl": "http://localhost:${docker.tests.sharePort}/share", + "adminUrl": "http://localhost:${docker.tests.sharePort}/share/keycloak", + "redirectUris": [ + "http://localhost:${docker.tests.sharePort}/share/*" + ], + "webOrigins": [ + "http://localhost:${docker.tests.sharePort}/share" + ], + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "a5b3e8bc-39cc-4ddd-8c8f-1c34e7a35975", + "publicClient": false, + "protocol": "openid-connect" } ], - "defaultDefaultClientScopes": [ - "role_list", - "roles", - "web-origins", - "email", - "profile" - ], - "defaultOptionalClientScopes": [ - "phone", - "address", - "offline_access", - "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" + "roles": { + "client": { + "alfresco": [ + { + "name": "admin", + "clientRole": true + } + ] + } }, - "smtpServer": { - - }, - "eventsEnabled": false, - "eventsListeners": [ - "jboss-logging" - ], - "enabledEventTypes": [], - "adminEventsEnabled": false, - "adminEventsDetailsEnabled": false, - "components": { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [{ - "id": "43a864c4-c4fa-4057-bf87-2ca409cde736", - "name": "Max Clients Limit", - "providerId": "max-clients", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - "max-clients": [ - "200" - ] - } - }, - { - "id": "6d4772af-f62e-40e9-8370-44aebf0d694d", - "name": "Consent Required", - "providerId": "consent-required", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - - } - }, - { - "id": "d474b02e-7d04-41c1-9c01-328221daa836", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "authenticated", - "subComponents": { - - }, - "config": { - "allow-default-scopes": [ - "true" - ] - } - }, - { - "id": "2f6ce962-4ad2-479b-87b2-35ea971039b1", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "authenticated", - "subComponents": { - - }, - "config": { - "allowed-protocol-mapper-types": [ - "oidc-address-mapper", - "oidc-sha256-pairwise-sub-mapper", - "oidc-usermodel-property-mapper", - "oidc-usermodel-attribute-mapper", - "saml-user-property-mapper", - "saml-user-attribute-mapper", - "saml-role-list-mapper", - "oidc-full-name-mapper" - ] - } - }, - { - "id": "3f7ae6b8-63c8-4ddf-82d8-afebf153a41a", - "name": "Full Scope Disabled", - "providerId": "scope", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - - } - }, - { - "id": "49326837-fe7d-47d6-85e7-5dd4028f0cd3", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - "allowed-protocol-mapper-types": [ - "oidc-usermodel-property-mapper", - "saml-role-list-mapper", - "oidc-sha256-pairwise-sub-mapper", - "oidc-full-name-mapper", - "saml-user-property-mapper", - "oidc-usermodel-attribute-mapper", - "oidc-address-mapper", - "saml-user-attribute-mapper" - ] - } - }, - { - "id": "c76f5e11-0576-4512-abf4-2d0b7cd5f355", - "name": "Trusted Hosts", - "providerId": "trusted-hosts", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - "host-sending-registration-request-must-match": [ - "true" - ], - "client-uris-must-match": [ - "true" - ] - } - }, - { - "id": "144efd74-bbbd-4176-8760-0e0819a61e5c", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "anonymous", - "subComponents": { - - }, - "config": { - "allow-default-scopes": [ - "true" - ] - } - } - ], - "org.keycloak.keys.KeyProvider": [{ - "id": "005993b6-dcb3-4ebf-b19c-7287c740bb79", - "name": "rsa-generated", - "providerId": "rsa-generated", - "subComponents": { - - }, - "config": { - "priority": [ - "100" - ] - } - }, - { - "id": "865ea0f7-9411-4985-8516-a3a7112204f4", - "name": "aes-generated", - "providerId": "aes-generated", - "subComponents": { - - }, - "config": { - "priority": [ - "100" - ] - } - }, - { - "id": "7783eb59-57b1-491b-a570-934811ac95c3", - "name": "hmac-generated", - "providerId": "hmac-generated", - "subComponents": { - - }, - "config": { - "priority": [ - "100" - ], - "algorithm": [ - "HS256" - ] - } - } - ] - }, - "internationalizationEnabled": false, - "supportedLocales": [], - "authenticationFlows": [{ - "id": "50eda798-0ed6-4fd1-9071-977ca22b032f", - "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 + "groups": [ + { + "name": "Test A", + "subGroups": [ + { + "name": "Test AA" }, { - "authenticator": "idp-email-verification", - "requirement": "ALTERNATIVE", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "ALTERNATIVE", - "priority": 30, - "flowAlias": "Verify Existing Account by Re-authentication", - "userSetupAllowed": false, - "autheticatorFlow": true + "name": "Test AB" } ] }, { - "id": "49354897-5c61-4aca-8b08-0601202abf49", - "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 - }, + "name": "Test B", + "subGroups": [ { - "authenticator": "auth-otp-form", - "requirement": "OPTIONAL", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "name": "Test BA" } ] - }, - { - "id": "f23bad00-b78e-4262-a025-5b2ef1d09dc4", - "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": "15d11f2c-9f51-4e41-8ca7-020b7b9e9335", - "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": "6846e2ce-b014-4296-a111-6f68ca10c985", - "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 - }, - { - "authenticator": "direct-grant-validate-otp", - "requirement": "OPTIONAL", - "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "9425e1d1-4533-413d-83c5-38c9657a355f", - "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": "eb15d55b-a601-493c-9f49-069695624ada", - "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 - }, - { - "authenticatorConfig": "create unique user config", - "authenticator": "idp-create-user-if-unique", - "requirement": "ALTERNATIVE", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "ALTERNATIVE", - "priority": 30, - "flowAlias": "Handle Existing Account", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "4fa685ea-65dd-4019-b3a3-a5f95b36e9f4", - "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 - }, - { - "authenticator": "auth-otp-form", - "requirement": "OPTIONAL", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "8edbb281-f132-4625-bf15-ebc314dd0c5d", - "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 - }, - { - "authenticator": "basic-auth", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "basic-auth-otp", - "requirement": "DISABLED", - "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "auth-spnego", - "requirement": "DISABLED", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "88374fbb-95fa-4bd5-940a-1289a9a051f6", - "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": "088ede2e-2dce-466d-b25f-62cc07c12bee", - "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": "065e575d-20fe-45e1-ab7d-d54ef056db8e", - "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 - }, - { - "authenticator": "reset-otp", - "requirement": "OPTIONAL", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "e1f9c5ba-5e45-4c51-a3cb-c10303b8c02e", - "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": "1593e111-7e5e-4ee2-b33d-f459834e4e3b", - "alias": "create unique user config", - "config": { - "require.password.update.after.registration": "false" + "users": [ + { + "id": "service-account-alfresco", + "serviceAccountClientId": "alfresco", + "username": "service-account-alfresco", + "enabled": true, + "email": "service-account-alfresco@muster.com", + "realmRoles": [ + "offline_access", + "uma_authorization" + ], + "clientRoles": { + "account": [ + "view-profile", + "manage-account" + ], + "realm-management": [ + "view-users", + "view-clients" + ] } }, { - "id": "ae5f6b14-fb84-4320-90a4-da8c80c379bf", - "alias": "review profile config", - "config": { - "update.profile.on.first.login": "missing" + "id": "mmustermann", + "username": "mmustermann", + "enabled": true, + "email": "max.mustermann@muster.com", + "firstName": "Max", + "lastName": "Mustermann", + "credentials": [ + { + "type": "password", + "value": "mmustermann" + } + ], + "realmRoles": [ + "user" + ], + "clientRoles": { + "account": [ + "view-profile", + "manage-account" + ] + }, + "groups": [ + "/Test A/Test AB", + "/Test B/Test BA" + ] + }, + { + "id": "jdoe", + "username": "jdoe", + "enabled": true, + "email": "john.doe@muster.com", + "firstName": "John", + "lastName": "Doe", + "credentials": [ + { + "type": "password", + "value": "jdoe" + } + ], + "realmRoles": [ + "user" + ], + "clientRoles": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + { + "id": "ssuper", + "username": "ssuper", + "enabled": true, + "email": "suzy.super@muster.com", + "firstName": "Suzy", + "lastName": "Super", + "credentials": [ + { + "type": "password", + "value": "ssuper" + } + ], + "realmRoles": [ + "user" + ], + "clientRoles": { + "account": [ + "view-profile", + "manage-account" + ], + "alfresco": [ + "admin" + ] } } - ], - "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": { - - } - } - ], - "browserFlow": "browser", - "registrationFlow": "registration", - "directGrantFlow": "direct grant", - "resetCredentialsFlow": "reset credentials", - "clientAuthenticationFlow": "clients", - "dockerAuthenticationFlow": "docker auth", - "attributes": { - "_browser_header.xXSSProtection": "1; mode=block", - "_browser_header.xFrameOptions": "SAMEORIGIN", - "_browser_header.strictTransportSecurity": "max-age=31536000; includeSubDomains", - "permanentLockout": "false", - "quickLoginCheckMilliSeconds": "1000", - "_browser_header.xRobotsTag": "none", - "maxFailureWaitSeconds": "900", - "minimumQuickLoginWaitSeconds": "60", - "failureFactor": "30", - "actionTokenGeneratedByUserLifespan": "300", - "maxDeltaTimeSeconds": "43200", - "_browser_header.xContentTypeOptions": "nosniff", - "offlineSessionMaxLifespan": "5184000", - "actionTokenGeneratedByAdminLifespan": "43200", - "_browser_header.contentSecurityPolicyReportOnly": "", - "bruteForceProtected": "false", - "_browser_header.contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "waitIncrementSeconds": "60", - "offlineSessionMaxLifespanEnabled": "false" - }, - "keycloakVersion": "6.0.1", - "userManagedAccessAllowed": false + ] } \ No newline at end of file diff --git a/share/src/test/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigTest.java b/share/src/test/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigTest.java index 3659bc1..b934283 100644 --- a/share/src/test/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigTest.java +++ b/share/src/test/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigTest.java @@ -20,12 +20,14 @@ import java.util.Map; import org.junit.Assert; import org.junit.Test; -import org.keycloak.representations.adapters.config.AdapterConfig; import org.springframework.extensions.config.Config; +import org.springframework.extensions.config.ConfigElement; import org.springframework.extensions.config.ConfigSource; import org.springframework.extensions.config.source.UrlConfigSource; import org.springframework.extensions.config.xml.XMLConfigService; +import de.acosix.alfresco.keycloak.share.deps.keycloak.representations.adapters.config.AdapterConfig; + /** * @author Axel Faust */ @@ -43,8 +45,9 @@ public class KeycloakAdapterConfigTest final Config keycloakConfigSection = configService.getConfig(KeycloakConfigConstants.KEYCLOAK_CONFIG_SECTION_NAME); - final KeycloakAuthenticationConfigElement keycloakAuthConfig = (KeycloakAuthenticationConfigElement) keycloakConfigSection - .getConfigElement(KeycloakAuthenticationConfigElement.NAME); + final ConfigElement keycloakAuthConfigEl = keycloakConfigSection.getConfigElement(KeycloakAuthenticationConfigElement.NAME); + Assert.assertTrue(keycloakAuthConfigEl instanceof KeycloakAuthenticationConfigElement); + final KeycloakAuthenticationConfigElement keycloakAuthConfig = (KeycloakAuthenticationConfigElement) keycloakAuthConfigEl; Assert.assertTrue(keycloakAuthConfig.getEnhanceLoginForm()); Assert.assertTrue(keycloakAuthConfig.getEnableSsoFilter()); @@ -89,8 +92,9 @@ public class KeycloakAdapterConfigTest final Config keycloakConfigSection = configService.getConfig(KeycloakConfigConstants.KEYCLOAK_CONFIG_SECTION_NAME); - final KeycloakAuthenticationConfigElement keycloakAuthConfig = (KeycloakAuthenticationConfigElement) keycloakConfigSection - .getConfigElement(KeycloakAuthenticationConfigElement.NAME); + final ConfigElement keycloakAuthConfigEl = keycloakConfigSection.getConfigElement(KeycloakAuthenticationConfigElement.NAME); + Assert.assertTrue(keycloakAuthConfigEl instanceof KeycloakAuthenticationConfigElement); + final KeycloakAuthenticationConfigElement keycloakAuthConfig = (KeycloakAuthenticationConfigElement) keycloakAuthConfigEl; Assert.assertFalse(keycloakAuthConfig.getEnhanceLoginForm()); Assert.assertFalse(keycloakAuthConfig.getEnableSsoFilter()); diff --git a/share/src/test/resources/default-config.xml b/share/src/test/resources/default-config.xml index d89601b..af86ce2 100644 --- a/share/src/test/resources/default-config.xml +++ b/share/src/test/resources/default-config.xml @@ -50,7 +50,7 @@ - + 60000