diff --git a/adapters/oidc/pom.xml b/adapters/oidc/pom.xml index 084232e5134..c563c76887d 100755 --- a/adapters/oidc/pom.xml +++ b/adapters/oidc/pom.xml @@ -38,9 +38,6 @@ js servlet-filter jakarta-servlet-filter - spring-boot2 - spring-boot-adapter-core - spring-boot-container-bundle spring-security undertow wildfly diff --git a/adapters/oidc/spring-boot-adapter-core/pom.xml b/adapters/oidc/spring-boot-adapter-core/pom.xml deleted file mode 100755 index ea1f9c6a673..00000000000 --- a/adapters/oidc/spring-boot-adapter-core/pom.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - keycloak-parent - org.keycloak - 999.0.0-SNAPSHOT - ../../../pom.xml - - 4.0.0 - - keycloak-spring-boot-adapter-core - Keycloak Spring Boot Adapter Core - - - - 2.0.5.RELEASE - - - - - org.jboss.logging - jboss-logging - - - org.keycloak - keycloak-core - - - org.keycloak - spring-boot-container-bundle - ${project.version} - true - compile - - - org.keycloak - keycloak-spring-security-adapter - ${project.version} - compile - true - - - org.springframework.boot - spring-boot-starter-web - ${spring-boot.version} - compile - true - - - io.undertow - undertow-servlet - compile - true - - - org.eclipse.jetty - jetty-server - ${jetty9.version} - compile - true - - - - org.eclipse.jetty - jetty-security - ${jetty9.version} - compile - true - - - - org.eclipse.jetty - jetty-webapp - ${jetty9.version} - compile - true - - - junit - junit - test - - - org.springframework.boot - spring-boot-configuration-processor - true - ${spring-boot.version} - - - diff --git a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakBaseSpringBootConfiguration.java b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakBaseSpringBootConfiguration.java deleted file mode 100755 index 92234c106b8..00000000000 --- a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakBaseSpringBootConfiguration.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 org.keycloak.adapters.springboot; - -import io.undertow.servlet.api.DeploymentInfo; -import io.undertow.servlet.api.SecurityInfo.EmptyRoleSemantic; -import io.undertow.servlet.api.WebResourceCollection; -import org.apache.catalina.Context; -import org.apache.tomcat.util.descriptor.web.LoginConfig; -import org.apache.tomcat.util.descriptor.web.SecurityCollection; -import org.apache.tomcat.util.descriptor.web.SecurityConstraint; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.HandlerList; -import org.eclipse.jetty.server.handler.HandlerWrapper; -import org.eclipse.jetty.util.security.Constraint; -import org.eclipse.jetty.webapp.WebAppContext; -import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator; -import org.keycloak.adapters.undertow.KeycloakServletExtension; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -/** - * Keycloak authentication base integration for Spring Boot - base to be extended for particular boot versions. - */ -public class KeycloakBaseSpringBootConfiguration { - - protected KeycloakSpringBootProperties keycloakProperties; - - @Autowired - public void setKeycloakSpringBootProperties(KeycloakSpringBootProperties keycloakProperties) { - this.keycloakProperties = keycloakProperties; - KeycloakSpringBootConfigResolverWrapper.setAdapterConfig(keycloakProperties); - } - - @Autowired - public void setApplicationContext(ApplicationContext context) { - KeycloakSpringBootConfigResolverWrapper.setApplicationContext(context); - } - - static class KeycloakBaseUndertowDeploymentInfoCustomizer { - - protected final KeycloakSpringBootProperties keycloakProperties; - - public KeycloakBaseUndertowDeploymentInfoCustomizer(KeycloakSpringBootProperties keycloakProperties) { - this.keycloakProperties = keycloakProperties; - } - - public void customize(DeploymentInfo deploymentInfo) { - - io.undertow.servlet.api.LoginConfig loginConfig = new io.undertow.servlet.api.LoginConfig(keycloakProperties.getRealm()); - loginConfig.addFirstAuthMethod("KEYCLOAK"); - - deploymentInfo.setLoginConfig(loginConfig); - - deploymentInfo.addInitParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolverWrapper.class.getName()); - - - /* Support for '*' as all roles allowed - * We clear out the role in the SecurityConstraints - * and set the EmptyRoleSemantic to Authenticate - * But we will set EmptyRoleSemantic to DENY (default) - * if roles are non existing or left empty - */ - Iterator it = this.getSecurityConstraints().iterator(); - while (it.hasNext()) { - io.undertow.servlet.api.SecurityConstraint securityConstraint = it.next(); - Set rolesAllowed = securityConstraint.getRolesAllowed(); - - if (rolesAllowed.contains("*") || rolesAllowed.contains("**") ) { - io.undertow.servlet.api.SecurityConstraint allRolesAllowed = new io.undertow.servlet.api.SecurityConstraint(); - allRolesAllowed.setEmptyRoleSemantic(EmptyRoleSemantic.AUTHENTICATE); - allRolesAllowed.setTransportGuaranteeType(securityConstraint.getTransportGuaranteeType()); - for (WebResourceCollection wr : securityConstraint.getWebResourceCollections()) { - allRolesAllowed.addWebResourceCollection(wr); - } - deploymentInfo.addSecurityConstraint(allRolesAllowed); - } else // left empty will fall back on default EmptyRoleSemantic.DENY - deploymentInfo.addSecurityConstraint(securityConstraint); - - } - deploymentInfo.addServletExtension(new KeycloakServletExtension()); - } - - private List getSecurityConstraints() { - - List undertowSecurityConstraints = new ArrayList(); - for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) { - - io.undertow.servlet.api.SecurityConstraint undertowSecurityConstraint = new io.undertow.servlet.api.SecurityConstraint(); - undertowSecurityConstraint.addRolesAllowed(constraintDefinition.getAuthRoles()); - - for (KeycloakSpringBootProperties.SecurityCollection collectionDefinition : constraintDefinition.getSecurityCollections()) { - - WebResourceCollection webResourceCollection = new WebResourceCollection(); - webResourceCollection.addHttpMethods(collectionDefinition.getMethods()); - webResourceCollection.addHttpMethodOmissions(collectionDefinition.getOmittedMethods()); - webResourceCollection.addUrlPatterns(collectionDefinition.getPatterns()); - - undertowSecurityConstraint.addWebResourceCollections(webResourceCollection); - - } - - undertowSecurityConstraints.add(undertowSecurityConstraint); - } - return undertowSecurityConstraints; - } - } - - static class KeycloakBaseJettyServerCustomizer { - - protected final KeycloakSpringBootProperties keycloakProperties; - - public KeycloakBaseJettyServerCustomizer(KeycloakSpringBootProperties keycloakProperties) { - this.keycloakProperties = keycloakProperties; - } - - public void customize(Server server) { - - KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator(); - keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolverWrapper()); - - /* see org.eclipse.jetty.webapp.StandardDescriptorProcessor#visitSecurityConstraint for an example - on how to map servlet spec to Constraints */ - - List jettyConstraintMappings = new ArrayList(); - for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) { - - for (KeycloakSpringBootProperties.SecurityCollection securityCollectionDefinition : constraintDefinition - .getSecurityCollections()) { - // securityCollection matches servlet spec's web-resource-collection - Constraint jettyConstraint = new Constraint(); - - if (constraintDefinition.getAuthRoles().size() > 0) { - jettyConstraint.setAuthenticate(true); - jettyConstraint.setRoles(constraintDefinition.getAuthRoles().toArray(new String[0])); - } - - jettyConstraint.setName(securityCollectionDefinition.getName()); - - // according to the servlet spec each security-constraint has at least one URL pattern - for(String pattern : securityCollectionDefinition.getPatterns()) { - - /* the following code is asymmetric as Jetty's ConstraintMapping accepts only one allowed HTTP method, - but multiple omitted methods. Therefore we add one ConstraintMapping for each allowed - mapping but only one mapping in the cases of omitted methods or no methods. - */ - - if (securityCollectionDefinition.getMethods().size() > 0) { - // according to the servlet spec we have either methods ... - for(String method : securityCollectionDefinition.getMethods()) { - ConstraintMapping jettyConstraintMapping = new ConstraintMapping(); - jettyConstraintMappings.add(jettyConstraintMapping); - - jettyConstraintMapping.setConstraint(jettyConstraint); - jettyConstraintMapping.setPathSpec(pattern); - jettyConstraintMapping.setMethod(method); - } - } else if (securityCollectionDefinition.getOmittedMethods().size() > 0){ - // ... omitted methods ... - ConstraintMapping jettyConstraintMapping = new ConstraintMapping(); - jettyConstraintMappings.add(jettyConstraintMapping); - - jettyConstraintMapping.setConstraint(jettyConstraint); - jettyConstraintMapping.setPathSpec(pattern); - jettyConstraintMapping.setMethodOmissions( - securityCollectionDefinition.getOmittedMethods().toArray(new String[0])); - } else { - // ... or no methods at all - ConstraintMapping jettyConstraintMapping = new ConstraintMapping(); - jettyConstraintMappings.add(jettyConstraintMapping); - - jettyConstraintMapping.setConstraint(jettyConstraint); - jettyConstraintMapping.setPathSpec(pattern); - } - - } - - } - } - - WebAppContext webAppContext = server.getBean(WebAppContext.class); - //if not found as registered bean let's try the handler - if(webAppContext==null){ - webAppContext = getWebAppContext(server.getHandlers()); - } - - ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler(); - securityHandler.setConstraintMappings(jettyConstraintMappings); - securityHandler.setAuthenticator(keycloakJettyAuthenticator); - - webAppContext.setSecurityHandler(securityHandler); - } - - private WebAppContext getWebAppContext(Handler... handlers) { - for (Handler handler : handlers) { - if (handler instanceof WebAppContext) { - return (WebAppContext) handler; - } else if (handler instanceof HandlerList) { - return getWebAppContext(((HandlerList) handler).getHandlers()); - } else if (handler instanceof HandlerCollection) { - return getWebAppContext(((HandlerCollection) handler).getHandlers()); - } else if (handler instanceof HandlerWrapper) { - return getWebAppContext(((HandlerWrapper) handler).getHandlers()); - } - } - throw new RuntimeException("No WebAppContext found in Jetty server handlers"); - } - } - - static class KeycloakBaseTomcatContextCustomizer { - - protected final KeycloakSpringBootProperties keycloakProperties; - - public KeycloakBaseTomcatContextCustomizer(KeycloakSpringBootProperties keycloakProperties) { - this.keycloakProperties = keycloakProperties; - } - - public void customize(Context context) { - LoginConfig loginConfig = new LoginConfig(); - loginConfig.setAuthMethod("KEYCLOAK"); - context.setLoginConfig(loginConfig); - - Set authRoles = new HashSet(); - for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) { - for (String authRole : constraint.getAuthRoles()) { - if (!authRoles.contains(authRole)) { - context.addSecurityRole(authRole); - authRoles.add(authRole); - } - } - } - - for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) { - SecurityConstraint tomcatConstraint = new SecurityConstraint(); - for (String authRole : constraint.getAuthRoles()) { - tomcatConstraint.addAuthRole(authRole); - if(authRole.equals("*") || authRole.equals("**")) { - // For some reasons embed tomcat don't set the auth constraint on true when wildcard is used - tomcatConstraint.setAuthConstraint(true); - } - } - - for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) { - SecurityCollection tomcatSecCollection = new SecurityCollection(); - - if (collection.getName() != null) { - tomcatSecCollection.setName(collection.getName()); - } - if (collection.getDescription() != null) { - tomcatSecCollection.setDescription(collection.getDescription()); - } - - for (String pattern : collection.getPatterns()) { - tomcatSecCollection.addPattern(pattern); - } - - for (String method : collection.getMethods()) { - tomcatSecCollection.addMethod(method); - } - - for (String method : collection.getOmittedMethods()) { - tomcatSecCollection.addOmittedMethod(method); - } - - tomcatConstraint.addCollection(tomcatSecCollection); - } - - context.addConstraint(tomcatConstraint); - } - - context.addParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolverWrapper.class.getName()); - } - } -} diff --git a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolver.java b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolver.java deleted file mode 100755 index bd425e2650d..00000000000 --- a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolver.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 org.keycloak.adapters.springboot; - -import org.keycloak.adapters.KeycloakDeployment; -import org.keycloak.adapters.KeycloakDeploymentBuilder; -import org.keycloak.adapters.OIDCHttpFacade; -import org.keycloak.representations.adapters.config.AdapterConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class KeycloakSpringBootConfigResolver implements org.keycloak.adapters.KeycloakConfigResolver { - - private KeycloakDeployment keycloakDeployment; - - @Autowired(required=false) - private AdapterConfig adapterConfig; - - @Override - public KeycloakDeployment resolve(OIDCHttpFacade.Request request) { - if (keycloakDeployment != null) { - return keycloakDeployment; - } - - keycloakDeployment = KeycloakDeploymentBuilder.build(adapterConfig); - - return keycloakDeployment; - } - - void setAdapterConfig(AdapterConfig adapterConfig) { - this.adapterConfig = adapterConfig; - } -} diff --git a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolverWrapper.java b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolverWrapper.java deleted file mode 100644 index c14dbfe6cd0..00000000000 --- a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfigResolverWrapper.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 org.keycloak.adapters.springboot; - -import org.keycloak.adapters.KeycloakConfigResolver; -import org.keycloak.adapters.springsecurity.config.KeycloakSpringConfigResolverWrapper; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.context.ApplicationContext; - -/** - *

A specific implementation of {@link KeycloakSpringConfigResolverWrapper} that first tries to register any {@link KeycloakConfigResolver} - * instance provided by the application. if none is provided, {@link KeycloakSpringBootConfigResolver} is set. - * - *

This implementation is specially useful when using Spring Boot and Spring Security in the same application where the same {@link KeycloakConfigResolver} - * instance must be used across the different stacks. - * - * @author Pedro Igor - */ -public class KeycloakSpringBootConfigResolverWrapper extends KeycloakSpringConfigResolverWrapper { - - private static ApplicationContext context; - private static KeycloakSpringBootProperties adapterConfig; - - public KeycloakSpringBootConfigResolverWrapper() { - super(new KeycloakSpringBootConfigResolver()); - try { - setDelegate(context.getBean(KeycloakConfigResolver.class)); - } catch (NoSuchBeanDefinitionException ignore) { - } - if (getDelegate() instanceof KeycloakSpringBootConfigResolver) { - KeycloakSpringBootConfigResolver.class.cast(getDelegate()).setAdapterConfig(adapterConfig); - } - } - - public static void setApplicationContext(ApplicationContext context) { - KeycloakSpringBootConfigResolverWrapper.context = context; - } - - public static void setAdapterConfig(KeycloakSpringBootProperties adapterConfig) { - KeycloakSpringBootConfigResolverWrapper.adapterConfig = adapterConfig; - } -} diff --git a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootProperties.java b/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootProperties.java deleted file mode 100644 index 9c28a9a7311..00000000000 --- a/adapters/oidc/spring-boot-adapter-core/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootProperties.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 org.keycloak.adapters.springboot; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import org.keycloak.representations.adapters.config.AdapterConfig; -import org.springframework.boot.context.properties.ConfigurationProperties; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@ConfigurationProperties(prefix = "keycloak", ignoreUnknownFields = false) -public class KeycloakSpringBootProperties extends AdapterConfig { - - /* this is a dummy property to avoid re-rebinding problem with property keycloak.config.resolver - when using spring cloud - see KEYCLOAK-2977 */ - @JsonIgnore - private Map config = new HashMap(); - - /** - * Allow enabling of Keycloak Spring Boot adapter by configuration. - */ - private boolean enabled = true; - - public Map getConfig() { - return config; - } - - /** - * To provide Java EE security constraints - */ - private List securityConstraints = new ArrayList(); - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - /** - * This matches security-constraint of the servlet spec - */ - @ConfigurationProperties() - public static class SecurityConstraint { - /** - * A list of security collections - */ - private List securityCollections = new ArrayList(); - private List authRoles = new ArrayList(); - - public List getAuthRoles() { - return authRoles; - } - - public List getSecurityCollections() { - return securityCollections; - } - - public void setSecurityCollections(List securityCollections) { - this.securityCollections = securityCollections; - } - - public void setAuthRoles(List authRoles) { - this.authRoles = authRoles; - } - - } - - /** - * This matches web-resource-collection of the servlet spec - */ - @ConfigurationProperties() - public static class SecurityCollection { - /** - * The name of your security constraint - */ - private String name; - /** - * The description of your security collection - */ - private String description; - /** - * A list of URL patterns that should match to apply the security collection - */ - private List patterns = new ArrayList(); - /** - * A list of HTTP methods that applies for this security collection - */ - private List methods = new ArrayList(); - /** - * A list of HTTP methods that will be omitted for this security collection - */ - private List omittedMethods = new ArrayList(); - - public List getPatterns() { - return patterns; - } - - public List getMethods() { - return methods; - } - - public String getDescription() { - return description; - } - - public String getName() { - return name; - } - - public List getOmittedMethods() { - return omittedMethods; - } - - public void setName(String name) { - this.name = name; - } - - public void setDescription(String description) { - this.description = description; - } - - public void setPatterns(List patterns) { - this.patterns = patterns; - } - - public void setMethods(List methods) { - this.methods = methods; - } - - public void setOmittedMethods(List omittedMethods) { - this.omittedMethods = omittedMethods; - } - } - - public List getSecurityConstraints() { - return securityConstraints; - } - - public void setSecurityConstraints(List securityConstraints) { - this.securityConstraints = securityConstraints; - } -} diff --git a/adapters/oidc/spring-boot-container-bundle/pom.xml b/adapters/oidc/spring-boot-container-bundle/pom.xml deleted file mode 100644 index b45be6c01ec..00000000000 --- a/adapters/oidc/spring-boot-container-bundle/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - 4.0.0 - - keycloak-parent - org.keycloak - 999.0.0-SNAPSHOT - ../../../pom.xml - - spring-boot-container-bundle - jar - - - org.keycloak - keycloak-adapter-core - compile - - - org.keycloak - keycloak-undertow-adapter - compile - - - org.keycloak - keycloak-jetty94-adapter - compile - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - - - org.keycloak:keycloak-undertow-adapter - org.keycloak:keycloak-jetty94-adapter - org.keycloak:keycloak-undertow-adapter - org.keycloak:keycloak-undertow-adapter-spi - org.keycloak:keycloak-jetty-core - org.keycloak:keycloak-jetty-adapter-spi - - - true - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - true - org.keycloak:keycloak-adapter-core - - - - - diff --git a/adapters/oidc/spring-boot2/.gitignore b/adapters/oidc/spring-boot2/.gitignore deleted file mode 100644 index 00d2ab71ddb..00000000000 --- a/adapters/oidc/spring-boot2/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/.apt_generated/ -/.apt_generated_tests/ diff --git a/adapters/oidc/spring-boot2/pom.xml b/adapters/oidc/spring-boot2/pom.xml deleted file mode 100755 index 86115f6004f..00000000000 --- a/adapters/oidc/spring-boot2/pom.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - keycloak-parent - org.keycloak - 999.0.0-SNAPSHOT - ../../../pom.xml - - 4.0.0 - - keycloak-spring-boot-2-adapter - Keycloak Spring Boot 2 Integration - - - - 2.0.5.RELEASE - 5.0.2.RELEASE - 1.9.5 - - - - - - org.keycloak - keycloak-spring-boot-adapter-core - - - - org.jboss.logging - jboss-logging - - - org.keycloak - keycloak-core - - - org.keycloak - spring-boot-container-bundle - ${project.version} - true - compile - - - org.keycloak - keycloak-spring-security-adapter - ${project.version} - compile - - - com.fasterxml.jackson.core - jackson-databind - provided - - - com.fasterxml.jackson.core - jackson-annotations - provided - - - org.springframework - spring-core - ${spring.version} - provided - - - org.springframework.boot - spring-boot-starter-web - ${spring-boot.version} - - - io.undertow - undertow-servlet - compile - true - - - org.eclipse.jetty - jetty-server - ${jetty9.version} - compile - true - - - - org.eclipse.jetty - jetty-security - ${jetty9.version} - compile - true - - - - org.eclipse.jetty - jetty-webapp - ${jetty9.version} - compile - true - - - junit - junit - test - - - org.springframework - spring-test - ${spring.version} - test - - - org.mockito - mockito-all - ${mockito.version} - test - - - org.springframework.boot - spring-boot-configuration-processor - true - ${spring-boot.version} - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - ${spring-boot.version} - - - diff --git a/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/KeycloakAutoConfiguration.java b/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/KeycloakAutoConfiguration.java deleted file mode 100755 index 6b16541a28b..00000000000 --- a/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/KeycloakAutoConfiguration.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 org.keycloak.adapters.springboot; - -import org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; -import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer; -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; -import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; -import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; -import org.springframework.boot.web.embedded.undertow.UndertowDeploymentInfoCustomizer; -import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; - - - - -/** - * Keycloak authentication integration for Spring Boot 2 - * - */ -@Configuration -@ConditionalOnWebApplication -@EnableConfigurationProperties(KeycloakSpringBootProperties.class) -@ConditionalOnProperty(value = "keycloak.enabled", matchIfMissing = true) -public class KeycloakAutoConfiguration extends KeycloakBaseSpringBootConfiguration { - - - @Bean - public WebServerFactoryCustomizer getKeycloakContainerCustomizer() { - return new WebServerFactoryCustomizer() { - @Override - public void customize(ConfigurableServletWebServerFactory configurableServletWebServerFactory) { - if(configurableServletWebServerFactory instanceof TomcatServletWebServerFactory){ - - TomcatServletWebServerFactory container = (TomcatServletWebServerFactory)configurableServletWebServerFactory; - container.addContextValves(new KeycloakAuthenticatorValve()); - container.addContextCustomizers(tomcatKeycloakContextCustomizer()); - - } else if (configurableServletWebServerFactory instanceof UndertowServletWebServerFactory){ - - UndertowServletWebServerFactory container = (UndertowServletWebServerFactory)configurableServletWebServerFactory; - container.addDeploymentInfoCustomizers(undertowKeycloakContextCustomizer()); - - } else if (configurableServletWebServerFactory instanceof JettyServletWebServerFactory){ - - JettyServletWebServerFactory container = (JettyServletWebServerFactory)configurableServletWebServerFactory; - container.addServerCustomizers(jettyKeycloakServerCustomizer()); - } - } - - }; - } - - @Bean - @ConditionalOnClass(name = {"org.eclipse.jetty.webapp.WebAppContext"}) - public JettyServerCustomizer jettyKeycloakServerCustomizer() { - return new KeycloakJettyServerCustomizer(keycloakProperties); - } - - @Bean - @ConditionalOnClass(name = {"org.apache.catalina.startup.Tomcat"}) - public TomcatContextCustomizer tomcatKeycloakContextCustomizer() { - return new KeycloakTomcatContextCustomizer(keycloakProperties); - } - - @Bean - @ConditionalOnClass(name = {"io.undertow.Undertow"}) - public UndertowDeploymentInfoCustomizer undertowKeycloakContextCustomizer() { - return new KeycloakUndertowDeploymentInfoCustomizer(keycloakProperties); - } - - static class KeycloakJettyServerCustomizer extends KeycloakBaseJettyServerCustomizer implements JettyServerCustomizer { - - - public KeycloakJettyServerCustomizer(KeycloakSpringBootProperties keycloakProperties) { - super(keycloakProperties); - } - - } - - static class KeycloakTomcatContextCustomizer extends KeycloakBaseTomcatContextCustomizer implements TomcatContextCustomizer { - - public KeycloakTomcatContextCustomizer(KeycloakSpringBootProperties keycloakProperties) { - super(keycloakProperties); - } - } - - static class KeycloakUndertowDeploymentInfoCustomizer extends KeycloakBaseUndertowDeploymentInfoCustomizer implements UndertowDeploymentInfoCustomizer { - - public KeycloakUndertowDeploymentInfoCustomizer(KeycloakSpringBootProperties keycloakProperties){ - super(keycloakProperties); - } - } -} diff --git a/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizer.java b/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizer.java deleted file mode 100644 index ae4836c7139..00000000000 --- a/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizer.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.keycloak.adapters.springboot.client; - -import org.springframework.boot.web.client.RestTemplateCustomizer; -import org.springframework.web.client.RestTemplate; - -public class KeycloakRestTemplateCustomizer implements RestTemplateCustomizer { - - private final KeycloakSecurityContextClientRequestInterceptor keycloakInterceptor; - - public KeycloakRestTemplateCustomizer() { - this(new KeycloakSecurityContextClientRequestInterceptor()); - } - - protected KeycloakRestTemplateCustomizer( - KeycloakSecurityContextClientRequestInterceptor keycloakInterceptor - ) { - this.keycloakInterceptor = keycloakInterceptor; - } - - @Override - public void customize(RestTemplate restTemplate) { - restTemplate.getInterceptors().add(keycloakInterceptor); - } -} diff --git a/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptor.java b/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptor.java deleted file mode 100644 index 200a9035f1e..00000000000 --- a/adapters/oidc/spring-boot2/src/main/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptor.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.keycloak.adapters.springboot.client; - -import org.keycloak.KeycloakPrincipal; -import org.keycloak.KeycloakSecurityContext; -import org.springframework.http.HttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import java.io.IOException; -import java.security.Principal; - -/** - * Interceptor for {@link ClientHttpRequestExecution} objects created for server to server secured - * communication using OAuth2 bearer tokens issued by Keycloak. - * - * @author James McShane - * @version $Revision: 1 $ - */ -public class KeycloakSecurityContextClientRequestInterceptor implements ClientHttpRequestInterceptor { - - private static final String AUTHORIZATION_HEADER = "Authorization"; - - /** - * Returns the {@link KeycloakSecurityContext} from the Spring {@link ServletRequestAttributes}'s {@link Principal}. - * - * The principal must support retrieval of the KeycloakSecurityContext, so at this point, only {@link KeycloakPrincipal} - * values are supported - * - * @return the current KeycloakSecurityContext - */ - protected KeycloakSecurityContext getKeycloakSecurityContext() { - ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - Principal principal = attributes.getRequest().getUserPrincipal(); - if (principal == null) { - throw new IllegalStateException("Cannot set authorization header because there is no authenticated principal"); - } - if (!(principal instanceof KeycloakPrincipal)) { - throw new IllegalStateException( - String.format( - "Cannot set authorization header because the principal type %s does not provide the KeycloakSecurityContext", - principal.getClass())); - } - return ((KeycloakPrincipal) principal).getKeycloakSecurityContext(); - } - - @Override - public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { - KeycloakSecurityContext context = this.getKeycloakSecurityContext(); - httpRequest.getHeaders().set(AUTHORIZATION_HEADER, "Bearer " + context.getTokenString()); - return clientHttpRequestExecution.execute(httpRequest, bytes); - } -} diff --git a/adapters/oidc/spring-boot2/src/main/resources/META-INF/spring.factories b/adapters/oidc/spring-boot2/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 0c80e3bd8b2..00000000000 --- a/adapters/oidc/spring-boot2/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.keycloak.adapters.springboot.KeycloakAutoConfiguration \ No newline at end of file diff --git a/adapters/oidc/spring-boot2/src/test/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizerTest.java b/adapters/oidc/spring-boot2/src/test/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizerTest.java deleted file mode 100644 index e8e599e40d3..00000000000 --- a/adapters/oidc/spring-boot2/src/test/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizerTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.keycloak.adapters.springboot.client; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.web.client.RestTemplate; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -public class KeycloakRestTemplateCustomizerTest { - - private KeycloakRestTemplateCustomizer customizer; - private KeycloakSecurityContextClientRequestInterceptor interceptor = - mock(KeycloakSecurityContextClientRequestInterceptor.class); - - @Before - public void setup() { - customizer = new KeycloakRestTemplateCustomizer(interceptor); - } - - @Test - public void interceptorIsAddedToRequest() { - RestTemplate restTemplate = new RestTemplate(); - customizer.customize(restTemplate); - assertTrue(restTemplate.getInterceptors().contains(interceptor)); - } - -} diff --git a/adapters/oidc/spring-boot2/src/test/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptorTest.java b/adapters/oidc/spring-boot2/src/test/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptorTest.java deleted file mode 100644 index 689cc65274d..00000000000 --- a/adapters/oidc/spring-boot2/src/test/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptorTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 org.keycloak.adapters.springboot.client; - -import org.junit.Before; -import org.junit.Test; -import org.keycloak.KeycloakPrincipal; -import org.keycloak.KeycloakSecurityContext; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import java.security.Principal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.when; - -/** - * Keycloak spring boot client request factory tests. - */ -public class KeycloakSecurityContextClientRequestInterceptorTest { - - @Spy - private KeycloakSecurityContextClientRequestInterceptor factory; - - private MockHttpServletRequest servletRequest; - - @Mock - private KeycloakSecurityContext keycloakSecurityContext; - - @Mock - private KeycloakPrincipal keycloakPrincipal; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - servletRequest = new MockHttpServletRequest(); - RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(servletRequest)); - servletRequest.setUserPrincipal(keycloakPrincipal); - when(keycloakPrincipal.getKeycloakSecurityContext()).thenReturn(keycloakSecurityContext); - } - - @Test - public void testGetKeycloakSecurityContext() throws Exception { - KeycloakSecurityContext context = factory.getKeycloakSecurityContext(); - assertNotNull(context); - assertEquals(keycloakSecurityContext, context); - } - - @Test(expected = IllegalStateException.class) - public void testGetKeycloakSecurityContextInvalidPrincipal() throws Exception { - servletRequest.setUserPrincipal(new MarkerPrincipal()); - factory.getKeycloakSecurityContext(); - } - - @Test(expected = IllegalStateException.class) - public void testGetKeycloakSecurityContextNullAuthentication() throws Exception { - servletRequest.setUserPrincipal(null); - factory.getKeycloakSecurityContext(); - } - - private static class MarkerPrincipal implements Principal { - @Override - public String getName() { - return null; - } - } -} diff --git a/boms/adapter/pom.xml b/boms/adapter/pom.xml index 615afea0f67..7e297ed1251 100644 --- a/boms/adapter/pom.xml +++ b/boms/adapter/pom.xml @@ -69,26 +69,6 @@ keycloak-undertow-adapter ${project.version} - - org.keycloak - keycloak-spring-boot-2-adapter - ${project.version} - - - org.keycloak - spring-boot-container-bundle - ${project.version} - - - org.keycloak - keycloak-spring-security-adapter - ${project.version} - - - org.keycloak - keycloak-spring-boot-starter - ${project.version} - org.keycloak keycloak-authz-client diff --git a/docs/documentation/securing_apps/topics/oidc/java/java-adapters.adoc b/docs/documentation/securing_apps/topics/oidc/java/java-adapters.adoc index 42140accc9a..103927f277d 100644 --- a/docs/documentation/securing_apps/topics/oidc/java/java-adapters.adoc +++ b/docs/documentation/securing_apps/topics/oidc/java/java-adapters.adoc @@ -17,8 +17,6 @@ include::java-adapter-config.adoc[] endif::[] include::jboss-adapter.adoc[] -include::spring-boot-adapter.adoc[] - ifeval::[{project_community}==true] include::spring-security-adapter.adoc[] endif::[] diff --git a/docs/documentation/securing_apps/topics/oidc/java/spring-boot-adapter.adoc b/docs/documentation/securing_apps/topics/oidc/java/spring-boot-adapter.adoc deleted file mode 100644 index a2303ad00d6..00000000000 --- a/docs/documentation/securing_apps/topics/oidc/java/spring-boot-adapter.adoc +++ /dev/null @@ -1,98 +0,0 @@ -[[_spring_boot_adapter]] -==== Spring Boot adapter - -[WARNING] -==== -This adapter is deprecated and will be removed in a future release of Keycloak. No further enhancements or new features -will be added to this adapter. - -We recommend that you leverage the OAuth2/OpenID Connect support from Spring Security. - -For more details about how to integrate {project_name} with Spring Boot applications, consider looking at the -{quickstartRepo_link}[Keycloak Quickstart GitHub Repository]. -==== - - -[[_spring_boot_adapter_installation]] -===== Installing the Spring Boot adapter - -To be able to secure Spring Boot apps you must add the Keycloak Spring Boot adapter JAR to your app. -You then have to provide some extra configuration via normal Spring Boot configuration (`application.properties`). - -The Keycloak Spring Boot adapter takes advantage of Spring Boot's autoconfiguration so all you need to do is add this adapter Keycloak Spring Boot starter to your project. - -.Procedure - -. To add the starter to your project using Maven, add the following to your dependencies: -+ -[source,xml,subs="attributes+"] ----- - - org.keycloak - keycloak-spring-boot-starter - ----- - -. Add the Adapter BOM dependency: -+ -[source,xml,subs="attributes+"] ----- - - - - org.keycloak.bom - keycloak-adapter-bom - {project_versionMvn} - pom - import - - - ----- - - -Currently the following embedded containers are supported and do not require any extra dependencies if using the Starter: - -* Tomcat -* Undertow - -[[_spring_boot_adapter_configuration]] -===== Configuring the Spring Boot Adapter - -Use the procedure to configure your Spring Boot app to use {project_name}. - -.Procedure - -. Instead of a `keycloak.json` file, you configure the realm for the Spring Boot adapter via the normal Spring Boot configuration. For example: -+ -[source,subs="attributes+"] ----- -keycloak.realm = demorealm -keycloak.auth-server-url = http://127.0.0.1:8080{kc_base_path} -keycloak.ssl-required = external -keycloak.resource = demoapp -keycloak.credentials.secret = 11111111-1111-1111-1111-111111111111 -keycloak.use-resource-role-mappings = true ----- -+ -You can disable the Keycloak Spring Boot Adapter (for example in tests) by setting `keycloak.enabled = false`. - -. To configure a Policy Enforcer, unlike keycloak.json, use `policy-enforcer-config` instead of just `policy-enforcer`. - -. Specify the Jakarta EE security config that would normally go in the `web.xml`. -+ -The Spring Boot Adapter will set the `login-method` to `KEYCLOAK` and configure the `security-constraints` at startup time. Here's an example configuration: -+ -[source] ----- -keycloak.securityConstraints[0].authRoles[0] = admin -keycloak.securityConstraints[0].authRoles[1] = user -keycloak.securityConstraints[0].securityCollections[0].name = insecure stuff -keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /insecure - -keycloak.securityConstraints[1].authRoles[0] = admin -keycloak.securityConstraints[1].securityCollections[0].name = admin stuff -keycloak.securityConstraints[1].securityCollections[0].patterns[0] = /admin ----- - -WARNING: If you plan to deploy your Spring Application as a WAR then you should not use the Spring Boot Adapter and use the dedicated adapter for the application server or servlet container you are using. Your Spring Boot should also contain a `web.xml` file. diff --git a/docs/documentation/securing_apps/topics/oidc/java/spring-security-adapter.adoc b/docs/documentation/securing_apps/topics/oidc/java/spring-security-adapter.adoc index 3d7552e06ba..8b63c060342 100644 --- a/docs/documentation/securing_apps/topics/oidc/java/spring-security-adapter.adoc +++ b/docs/documentation/securing_apps/topics/oidc/java/spring-security-adapter.adoc @@ -294,99 +294,4 @@ public class RemoteProductService implements ProductService { return Arrays.asList(response.getBody()); } } ----- - -===== Spring Boot Integration - -The Spring Boot and the Spring Security adapters can be combined. - -If you are using the Keycloak Spring Boot Starter to make use of the Spring Security adapter you just need to add the Spring Security starter : - -[source,xml] ----- - - - org.springframework.boot - spring-boot-starter-security - - ----- - -====== Using Spring Boot Configuration - -By Default, the Spring Security Adapter looks for a `keycloak.json` configuration file. You can make sure it looks at the configuration provided by the Spring Boot Adapter by adding this bean: - -[source,java] ----- - -@Configuration -public class CustomKeycloakConfig { - - @Bean - public KeycloakConfigResolver keycloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } -} - ----- - -Do not declare the `KeycloakConfigResolver` bean in a configuration class that extends `KeycloakWebSecurityConfigurerAdapter` as this will cause a `Circular References` problem in Spring Boot starting with version 2.6.0. - -====== Avoid double bean registration - -Spring Boot attempts to eagerly register filter beans with the web application context. -Therefore, when running the Keycloak Spring Security adapter in a Spring Boot environment, it may be necessary to add ``FilterRegistrationBean``s to your security configuration to prevent the Keycloak filters from being registered twice. - -Spring Boot 2.1 also disables `spring.main.allow-bean-definition-overriding` by default. This can mean that an `BeanDefinitionOverrideException` will be encountered if a `Configuration` class extending `KeycloakWebSecurityConfigurerAdapter` registers a bean that is already detected by a `@ComponentScan`. This can be avoided by overriding the registration to use the Boot-specific `@ConditionalOnMissingBean` annotation, as with `HttpSessionManager` below. - -[source,java] ----- - - -@Configuration -@EnableWebSecurity -public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter -{ - ... - - @Bean - public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean( - KeycloakAuthenticationProcessingFilter filter) { - FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } - - @Bean - public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean( - KeycloakPreAuthActionsFilter filter) { - FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } - - @Bean - public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean( - KeycloakAuthenticatedActionsFilter filter) { - FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } - - @Bean - public FilterRegistrationBean keycloakSecurityContextRequestFilterBean( - KeycloakSecurityContextRequestFilter filter) { - FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } - - @Bean - @Override - @ConditionalOnMissingBean(HttpSessionManager.class) - protected HttpSessionManager httpSessionManager() { - return new HttpSessionManager(); - } - ... -} ----- +---- \ No newline at end of file diff --git a/docs/documentation/securing_apps/topics/overview/getting-started.adoc b/docs/documentation/securing_apps/topics/overview/getting-started.adoc index c49a725c6fe..888f2bc1a3d 100644 --- a/docs/documentation/securing_apps/topics/overview/getting-started.adoc +++ b/docs/documentation/securing_apps/topics/overview/getting-started.adoc @@ -15,7 +15,6 @@ ifeval::[{project_community}==true] * {quickstartRepo_link}/tree/latest/spring/rest-authz-resource-server[Spring Boot] * <<_jboss_adapter, {project_name} Wildfly Adapter>> (Deprecated) * <<_servlet_filter_adapter,{project_name} Servlet Filter>> (Deprecated) -* <<_spring_boot_adapter,{project_name} Spring Boot>> (Deprecated) * <<_spring_security_adapter,{project_name} Spring Security>> (Deprecated) endif::[] diff --git a/misc/pom.xml b/misc/pom.xml index 8c813fdc507..38b811c4cf2 100644 --- a/misc/pom.xml +++ b/misc/pom.xml @@ -12,7 +12,6 @@ keycloak-misc-parent pom - spring-boot-starter keycloak-test-helper diff --git a/misc/spring-boot-starter/keycloak-spring-boot-starter/pom.xml b/misc/spring-boot-starter/keycloak-spring-boot-starter/pom.xml deleted file mode 100644 index d3a97a4168c..00000000000 --- a/misc/spring-boot-starter/keycloak-spring-boot-starter/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - 4.0.0 - - org.keycloak - keycloak-spring-boot-starter-parent - 999.0.0-SNAPSHOT - - keycloak-spring-boot-starter - Keycloak :: Spring :: Boot :: Default :: Starter - Spring Boot Default Starter for Keycloak - - - 2.0.3.RELEASE - - - - - org.keycloak - keycloak-spring-boot-2-adapter - - - org.keycloak - keycloak-authz-client - - - org.springframework.boot - spring-boot-starter - ${spring-boot.version} - - - org.keycloak - spring-boot-container-bundle - - - org.keycloak - keycloak-spring-security-adapter - - - diff --git a/misc/spring-boot-starter/pom.xml b/misc/spring-boot-starter/pom.xml deleted file mode 100644 index b94cafa4a6d..00000000000 --- a/misc/spring-boot-starter/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - 4.0.0 - - keycloak-misc-parent - org.keycloak - 999.0.0-SNAPSHOT - - org.keycloak - keycloak-spring-boot-starter-parent - Keycloak :: Spring :: Boot - Support for using Keycloak in Spring Boot applications. - pom - - keycloak-spring-boot-starter - - - - - - org.keycloak.bom - keycloak-adapter-bom - ${project.version} - pom - import - - - - diff --git a/pom.xml b/pom.xml index 2db1233b58b..eb9727c7a04 100644 --- a/pom.xml +++ b/pom.xml @@ -216,9 +216,6 @@ 8.5.76 9.0.16 - - 2.7.14 - 0.21.5.RELEASE 2.0.3 @@ -1102,16 +1099,6 @@ keycloak-js-adapter-jar ${project.version} - - org.keycloak - keycloak-spring-boot-adapter-core - ${project.version} - - - org.keycloak - keycloak-spring-boot-2-adapter - ${project.version} - org.keycloak keycloak-saml-servlet-filter-adapter diff --git a/testsuite/integration-arquillian/HOW-TO-RUN.md b/testsuite/integration-arquillian/HOW-TO-RUN.md index f2adca7b5ad..d7b4358461b 100644 --- a/testsuite/integration-arquillian/HOW-TO-RUN.md +++ b/testsuite/integration-arquillian/HOW-TO-RUN.md @@ -339,19 +339,6 @@ that you need to use property `migration.mode` with the value `manual` . -Dmigration.mode=manual -## Spring Boot adapter tests - -Currently, we are testing Spring Boot with three different containers `Tomcat 8`, `Undertow` and `Jetty 9.4`. -We are testing with Spring Boot 2.7. The version is specified in [root pom.xml](../../pom.xml) (i.e. see property `spring-boot27.version`). -To run tests execute following command. Default version of Spring Boot is 2.7.x, there is also a profile `-Pspringboot27`. - -``` -mvn -f testsuite/integration-arquillian/tests/other/springboot-tests/pom.xml \ - clean test \ - -Dadapter.container=[tomcat|undertow|jetty94] \ - [-Pspringboot27] -``` - ## Disabling features Some features in Keycloak can be disabled. To run the testsuite with a specific feature disabled use the `auth.server.feature` system property. For example to run the tests with authorization disabled run: ``` diff --git a/testsuite/integration-arquillian/test-apps/pom.xml b/testsuite/integration-arquillian/test-apps/pom.xml index 320a3133d23..47f2da30af6 100644 --- a/testsuite/integration-arquillian/test-apps/pom.xml +++ b/testsuite/integration-arquillian/test-apps/pom.xml @@ -23,7 +23,6 @@ servlets-jakarta app-profile-jee cors - spring-boot-adapter-app fuse diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/pom.xml b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/pom.xml deleted file mode 100644 index b2ea91bfaca..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/pom.xml +++ /dev/null @@ -1,190 +0,0 @@ - - - - org.keycloak.testsuite - integration-arquillian-test-apps - 999.0.0-SNAPSHOT - - 4.0.0 - - spring-boot-adapter-app - - - UTF-8 - UTF-8 - 1.8 - ${jetty94.version} - ${undertow-legacy.version} - - 2.7 - - false - - 5006 - n - - - - - org.springframework.boot - spring-boot-starter-thymeleaf - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.boot - spring-boot-starter-web - - - - org.keycloak - keycloak-spring-boot-2-adapter - - - - javax.servlet - javax.servlet-api - - - - org.glassfish.jersey.core - jersey-common - 2.26 - - - - - - - - spring.boot.2.7 - - - true - - springboot-version - 2.7 - - - - - ${spring-boot27.version} - - - - - spring-boot-adapter-tomcat - - - org.springframework.boot - spring-boot-starter-web - - - org.keycloak - ${spring.boot.tomcat.adapter.artifactId} - ${spring.boot.adapter.version} - - - - - - spring-boot-adapter-undertow - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - - - org.springframework.boot - spring-boot-starter-undertow - ${spring-boot.version} - - - - org.keycloak - keycloak-undertow-adapter - ${spring.boot.adapter.version} - - - - - - spring-boot-adapter-jetty94 - - - ${jetty94.version} - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - - - - org.keycloak - keycloak-jetty94-adapter - ${spring.boot.adapter.version} - - - org.springframework.boot - spring-boot-starter-jetty - - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - - -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=${app.server.debug.suspend},address=${app.server.debug.port} - - - - - - - - - - org.springframework.boot - spring-boot-starter-parent - ${spring-boot27.version} - pom - import - - - org.eclipse.jetty - jetty-bom - ${jetty.version} - pom - - - - - diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/java/org/keycloak/AdminController.java b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/java/org/keycloak/AdminController.java deleted file mode 100644 index 85b2b2aad80..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/java/org/keycloak/AdminController.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.keycloak; - -import org.keycloak.adapters.RefreshableKeycloakSecurityContext; -import org.keycloak.common.util.Base64Url; -import org.keycloak.common.util.KeycloakUriBuilder; -import org.keycloak.common.util.Time; -import org.keycloak.jose.jws.JWSInput; -import org.keycloak.jose.jws.JWSInputException; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.RefreshToken; -import org.keycloak.util.JsonSerialization; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; -import org.springframework.web.context.request.WebRequest; - -import javax.servlet.http.HttpSession; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Map; -import java.util.UUID; - -@Controller -@RequestMapping(path = "/admin") -public class AdminController { - - private static Logger logger = LoggerFactory.getLogger(AdminController.class); - - @RequestMapping(path = "/TokenServlet", method = RequestMethod.GET) - public String showTokens(WebRequest req, Model model, @RequestParam Map attributes) throws IOException { - String timeOffset = attributes.get("timeOffset"); - if (!StringUtils.isEmpty(timeOffset)) { - int offset; - try { - offset = Integer.parseInt(timeOffset, 10); - } - catch (NumberFormatException e) { - offset = 0; - } - - Time.setOffset(offset); - } - - RefreshableKeycloakSecurityContext ctx = - (RefreshableKeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName(), WebRequest.SCOPE_REQUEST); - String accessTokenPretty = JsonSerialization.writeValueAsPrettyString(ctx.getToken()); - RefreshToken refreshToken; - try { - refreshToken = new JWSInput(ctx.getRefreshToken()).readJsonContent(RefreshToken.class); - } catch (JWSInputException e) { - throw new IOException(e); - } - String refreshTokenPretty = JsonSerialization.writeValueAsPrettyString(refreshToken); - - model.addAttribute("accessToken", accessTokenPretty); - model.addAttribute("refreshToken", refreshTokenPretty); - model.addAttribute("accessTokenString", ctx.getTokenString()); - - return "tokens"; - } - - @RequestMapping(path = "/SessionServlet", method = RequestMethod.GET) - public String sessionServlet(WebRequest webRequest, Model model) { - String counterString = (String) webRequest.getAttribute("counter", RequestAttributes.SCOPE_SESSION); - int counter = 0; - try { - counter = Integer.parseInt(counterString, 10); - } - catch (NumberFormatException ignored) { - } - - model.addAttribute("counter", counter); - - webRequest.setAttribute("counter", Integer.toString(counter+1), RequestAttributes.SCOPE_SESSION); - - return "session"; - } - - @RequestMapping(path = "/LinkServlet", method = RequestMethod.GET) - public String tokenController(WebRequest webRequest, - @RequestParam Map attributes, - Model model) { - - ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); - HttpSession httpSession = attr.getRequest().getSession(true); - -// response.addHeader("Cache-Control", "no-cache"); - - String responseAttr = attributes.get("response"); - - if (StringUtils.isEmpty(responseAttr)) { - String provider = attributes.get("provider"); - String realm = attributes.get("realm"); - KeycloakSecurityContext keycloakSession = - (KeycloakSecurityContext) webRequest.getAttribute( - KeycloakSecurityContext.class.getName(), - RequestAttributes.SCOPE_REQUEST); - AccessToken token = keycloakSession.getToken(); - String clientId = token.getIssuedFor(); - String nonce = UUID.randomUUID().toString(); - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - String input = nonce + token.getSessionState() + clientId + provider; - byte[] check = md.digest(input.getBytes(StandardCharsets.UTF_8)); - String hash = Base64Url.encode(check); - httpSession.setAttribute("hash", hash); - String redirectUri = KeycloakUriBuilder.fromUri("http://localhost:8280/admin/LinkServlet") - .queryParam("response", "true").build().toString(); - String accountLinkUrl = KeycloakUriBuilder.fromUri("http://localhost:8180/") - .path("/auth/realms/{realm}/broker/{provider}/link") - .queryParam("nonce", nonce) - .queryParam("hash", hash) - .queryParam("client_id", token.getIssuedFor()) - .queryParam("redirect_uri", redirectUri).build(realm, provider).toString(); - - return "redirect:" + accountLinkUrl; - } else { - String error = attributes.get("link_error"); - if (StringUtils.isEmpty(error)) - model.addAttribute("error", "Account linked"); - else - model.addAttribute("error", error); - - return "linking"; - } - } -} diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/java/org/keycloak/SpringBootAdapterApplication.java b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/java/org/keycloak/SpringBootAdapterApplication.java deleted file mode 100644 index 38332990344..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/java/org/keycloak/SpringBootAdapterApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.keycloak; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SpringBootAdapterApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringBootAdapterApplication.class, args); - } -} diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/application.properties b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/application.properties deleted file mode 100644 index 84de1bbcd47..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/application.properties +++ /dev/null @@ -1,12 +0,0 @@ -server.port=8280 - -keycloak.realm=test -keycloak.auth-server-url=http://localhost:8180/auth -keycloak.ssl-required=external -keycloak.resource=spring-boot-app -keycloak.credentials.secret=e3789ac5-bde6-4957-a7b0-612823dac101 -keycloak.realm-key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB - -keycloak.security-constraints[0].authRoles[0]=admin -keycloak.security-constraints[0].securityCollections[0].name=Admin zone -keycloak.security-constraints[0].securityCollections[0].patterns[0]=/admin/* \ No newline at end of file diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/static/admin/index.html b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/static/admin/index.html deleted file mode 100644 index acb47afb71d..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/static/admin/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - springboot admin page - - - -

You are now admin
- - - \ No newline at end of file diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/static/index.html b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/static/index.html deleted file mode 100644 index 5ca73039924..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/static/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - springboot test page - - - -
Click here to go admin
- - - \ No newline at end of file diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/linking.html b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/linking.html deleted file mode 100644 index 6c7d5bd2b68..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/linking.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - Linking page result - - - - - \ No newline at end of file diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/session.html b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/session.html deleted file mode 100644 index 9a7e52f027a..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/session.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - session counter page - - - - - \ No newline at end of file diff --git a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/tokens.html b/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/tokens.html deleted file mode 100644 index 09dee7263d2..00000000000 --- a/testsuite/integration-arquillian/test-apps/spring-boot-adapter-app/src/main/resources/templates/tokens.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - Tokens from spring boot - - - - - - - \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/pom.xml b/testsuite/integration-arquillian/tests/other/pom.xml index 0bd86fcd79c..3e35e9bf85c 100644 --- a/testsuite/integration-arquillian/tests/other/pom.xml +++ b/testsuite/integration-arquillian/tests/other/pom.xml @@ -142,12 +142,6 @@ sssd - - springboot - - springboot-tests - - webauthn diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/pom.xml b/testsuite/integration-arquillian/tests/other/springboot-tests/pom.xml deleted file mode 100644 index cd3ea630c6d..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/pom.xml +++ /dev/null @@ -1,249 +0,0 @@ - - - - integration-arquillian-tests-other - org.keycloak.testsuite - 999.0.0-SNAPSHOT - - 4.0.0 - - integration-arquillian-tests-springboot - - - tomcat - - - 2.7 - ${project.version} - - 5006 - n - mvn - - false - - - - - org.keycloak - keycloak-test-helper - ${project.version} - - - org.hamcrest - hamcrest - compile - - - - org.glassfish.jersey.core - jersey-common - 2.26 - - - - org.glassfish.jersey.core - jersey-client - 2.26 - - - - org.glassfish.jersey.inject - jersey-hk2 - 2.26 - - - - - - - test-springboot - - - - !settings.path - - - - - - - com.bazaarvoice.maven.plugins - process-exec-maven-plugin - 0.7 - - - - spring-boot-clean-install - generate-test-resources - - start - - - springboot-initialize - ../../../../test-apps/spring-boot-adapter-app - 0 - - ${maven.binary.path} - clean - install - -B - -Pspring-boot-adapter-${adapter.container} - -Dmaven.repo.local=${settings.localRepository} - -Dspringboot-version=${springboot.version.option} - -Dspring.boot.adapter.version=${spring.boot.adapter.version} - -Dinsecure.repositories=WARN - - - - - spring-boot-application-process - process-test-resources - - start - - - springboot - ../../../../test-apps/spring-boot-adapter-app - http://localhost:8280/index.html - 900 - - ${maven.binary.path} - spring-boot:run - -B - -Pspring-boot-adapter-${adapter.container} - -Dmaven.repo.local=${settings.localRepository} - -Dspringboot-version=${springboot.version.option} - -Dspring.boot.adapter.version=${spring.boot.adapter.version} - -Dapp.server.debug.port=${app.server.debug.port} - -Dapp.server.debug.suspend=${app.server.debug.suspend} - -Dinsecure.repositories=WARN - - - - - - kill-processes - post-integration-test - - stop-all - - - - - - - - - test-springboot-with-settings - - - - settings.path - - - - - -Dno-repo - - - - - - com.bazaarvoice.maven.plugins - process-exec-maven-plugin - 0.7 - - - - spring-boot-clean-install - generate-test-resources - - start - - - springboot-initialize - ../../../../test-apps/spring-boot-adapter-app - 0 - - ${maven.binary.path} - clean - install - -s - ${settings.path} - -B - -Pspring-boot-adapter-${adapter.container} - -Dmaven.repo.local=${settings.localRepository} - -Dspringboot-version=${springboot.version.option} - -Dspring.boot.adapter.version=${spring.boot.adapter.version} - -Dinsecure.repositories=WARN - ${repo.argument} - - - - - spring-boot-application-process - process-test-resources - - start - - - springboot - ../../../../test-apps/spring-boot-adapter-app - http://localhost:8280/index.html - 900 - - ${maven.binary.path} - spring-boot:run - -B - -s - ${settings.path} - -Pspring-boot-adapter-${adapter.container} - -Dmaven.repo.local=${settings.localRepository} - -Dspringboot-version=${springboot.version.option} - -Dspring.boot.adapter.version=${spring.boot.adapter.version} - -Dapp.server.debug.port=${app.server.debug.port} - -Dapp.server.debug.suspend=${app.server.debug.suspend} - -Dinsecure.repositories=WARN - ${repo.argument} - - - - - - kill-processes - post-integration-test - - stop-all - - - - - - - - - - springboot27 - - 2.7 - - - - - turn-on-repo-url - - - repo.url - - - - -Drepo.url=${repo.url} - - - - - - \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/AbstractSpringbootPage.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/AbstractSpringbootPage.java deleted file mode 100644 index c42e621bf29..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/AbstractSpringbootPage.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import org.keycloak.testsuite.pages.AbstractPage; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.core.IsEqual.equalTo; - -public abstract class AbstractSpringbootPage extends AbstractPage { - - protected String title; - - public AbstractSpringbootPage(String title) { - this.title = title; - } - - public void assertIsCurrent() { - assertThat(driver.getTitle().toLowerCase(), is(equalTo(title.toLowerCase()))); - } - - @Override - public boolean isCurrent() { - return driver.getTitle().equalsIgnoreCase(title); - } - - @Override - public void open() throws Exception { - } - -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/LinkingPage.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/LinkingPage.java deleted file mode 100644 index dfd2a2d8295..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/LinkingPage.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import org.keycloak.testsuite.pages.AbstractPage; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; - -public class LinkingPage extends AbstractSpringbootPage { - - public static final String PAGE_TITLE = "linking page result"; - - public LinkingPage() { - super(PAGE_TITLE); - } - - @FindBy(id = "error") - private WebElement errorMessage; - - - public String getErrorMessage() { - return errorMessage.getText(); - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SessionPage.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SessionPage.java deleted file mode 100644 index 8d9ffaa3c9f..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SessionPage.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import org.apache.commons.lang3.math.NumberUtils; -import org.keycloak.testsuite.pages.AbstractPage; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; - -public class SessionPage extends AbstractSpringbootPage { - - @FindBy(id = "counter") - private WebElement counterElement; - - public static final String PAGE_TITLE = "session counter page"; - - public SessionPage() { - super(PAGE_TITLE); - } - - public int getCounter() { - String counterString = counterElement.getText(); - - return NumberUtils.toInt(counterString, 0); - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SpringAdminPage.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SpringAdminPage.java deleted file mode 100644 index a3d10c53775..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SpringAdminPage.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; - -public class SpringAdminPage extends AbstractSpringbootPage { - - @FindBy(className = "test") - private WebElement testDiv; - - public static final String PAGE_TITLE = "springboot admin page"; - - public SpringAdminPage() { - super(PAGE_TITLE); - } - - public String getTestDivString() { - return testDiv.getText(); - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SpringApplicationPage.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SpringApplicationPage.java deleted file mode 100644 index 413ccae93a8..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/SpringApplicationPage.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; - -import static org.keycloak.testsuite.util.UIUtils.clickLink; - -public class SpringApplicationPage extends AbstractSpringbootPage { - - @FindBy(className = "test") - private WebElement testDiv; - - @FindBy(className = "adminlink") - private WebElement adminLink; - - public static final String PAGE_TITLE = "springboot test page"; - - public SpringApplicationPage() { - super(PAGE_TITLE); - } - - public void goAdmin() { - clickLink(adminLink); - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/TokenPage.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/TokenPage.java deleted file mode 100644 index 653cd51ee8b..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/main/java/org/keycloak/testsuite/springboot/TokenPage.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import java.net.URL; - -import org.keycloak.testsuite.adapter.page.AbstractShowTokensPage; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; - -public class TokenPage extends AbstractShowTokensPage { - - public static final String PAGE_TITLE = "tokens from spring boot"; - - @Override - public boolean isCurrent() { - return driver.getTitle().equalsIgnoreCase(PAGE_TITLE.toLowerCase()); - } - - public void assertIsCurrent() { - assertThat(driver.getTitle().toLowerCase(), is(equalTo(PAGE_TITLE))); - } - - @Override - public URL getInjectedUrl() { - return null; - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/AbstractSpringBootTest.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/AbstractSpringBootTest.java deleted file mode 100644 index cab6f94c03d..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/AbstractSpringBootTest.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import static org.hamcrest.Matchers.is; -import static org.keycloak.testsuite.admin.ApiUtil.assignRealmRoles; -import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient; -import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword; -import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.ws.rs.core.UriBuilder; - -import org.jboss.arquillian.graphene.page.Page; -import org.jboss.logging.Logger; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.keycloak.OAuth2Constants; -import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.admin.client.resource.RoleResource; -import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.representations.idm.RoleRepresentation; -import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.testsuite.AbstractKeycloakTest; -import org.keycloak.testsuite.Assert; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.arquillian.SuiteContext; -import org.keycloak.testsuite.auth.page.login.OIDCLogin; -import org.keycloak.testsuite.pages.InfoPage; -import org.keycloak.testsuite.pages.LoginPage; -import org.keycloak.testsuite.pages.LogoutConfirmPage; -import org.keycloak.testsuite.util.DroneUtils; -import org.keycloak.testsuite.util.WaitUtils; -import org.keycloak.util.TokenUtil; -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; - -public abstract class AbstractSpringBootTest extends AbstractKeycloakTest { - - static final String REALM_ID = "cd8ee421-5100-41ba-95dd-b27c8e5cf042"; - - static final String REALM_NAME = "test"; - - static final String CLIENT_ID = "spring-boot-app"; - static final String SECRET = "e3789ac5-bde6-4957-a7b0-612823dac101"; - - static final String APPLICATION_URL = "http://localhost:8280"; - static final String BASE_URL = APPLICATION_URL + "/admin"; - - static final String USER_LOGIN = "testuser"; - static final String USER_EMAIL = "user@email.test"; - static final String USER_PASSWORD = "user-password"; - - static final String CORRECT_ROLE = "admin"; - - static final String REALM_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5" + - "mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi7" + - "9NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"; - - static final String REALM_PRIVATE_KEY = "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3Bj" + - "LGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vj" + - "O2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jY" + - "lQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn" + - "9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEK" + - "Xalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2w" + - "Vl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJ" + - "AY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZ" + - "N39fOYAlo+nTixgeW7X8Y="; - - @Page - LoginPage loginPage; - - @Page - protected OIDCLogin testRealmLoginPage; - - @Page - protected LogoutConfirmPage logoutConfirmPage; - - @Page - protected InfoPage infoPage; - - @Page - SpringApplicationPage applicationPage; - - @Page - SpringAdminPage adminPage; - - @Page - TokenPage tokenPage; - - @Override - public void addTestRealms(List testRealms) { - RealmRepresentation realm = new RealmRepresentation(); - - realm.setId(REALM_ID); - realm.setRealm(REALM_NAME); - realm.setEnabled(true); - - realm.setPublicKey(REALM_PUBLIC_KEY); - realm.setPrivateKey(REALM_PRIVATE_KEY); - - realm.setClients(Collections.singletonList(createClient())); - - List eventListeners = new ArrayList<>(); - eventListeners.add("jboss-logging"); - eventListeners.add("event-queue"); - realm.setEventsListeners(eventListeners); - - testRealms.add(realm); - } - - private ClientRepresentation createClient() { - ClientRepresentation clientRepresentation = new ClientRepresentation(); - - clientRepresentation.setId(CLIENT_ID); - clientRepresentation.setSecret(SECRET); - - clientRepresentation.setBaseUrl(BASE_URL); - clientRepresentation.setRedirectUris(Collections.singletonList(BASE_URL + "/*")); - clientRepresentation.setAdminUrl(BASE_URL); - - return clientRepresentation; - } - - void addUser(String login, String email, String password, String... roles) { - UserRepresentation userRepresentation = new UserRepresentation(); - - userRepresentation.setUsername(login); - userRepresentation.setEmail(email); - userRepresentation.setEmailVerified(true); - userRepresentation.setEnabled(true); - - RealmResource realmResource = adminClient.realm(REALM_NAME); - String userId = createUserWithAdminClient(realmResource, userRepresentation); - - resetUserPassword(realmResource.users().get(userId), password, false); - - for (String role : roles) - assignRealmRoles(realmResource, userId, role); - } - - private String getAuthRoot(SuiteContext suiteContext) { - return suiteContext.getAuthServerInfo().getContextRoot().toString(); - } - - private String encodeUrl(String url) { - String result; - try { - result = URLEncoder.encode(url, "UTF-8"); - } catch (UnsupportedEncodingException e) { - result = url; - } - - return result; - } - - String getLogoutUrl() { - return getAuthRoot(suiteContext) - + "/auth/realms/" + REALM_NAME - + "/protocol/" + "openid-connect" - + "/logout"; - } - - void logout(String redirectUrl) { - String logoutUrl = getLogoutUrl(); - driver.navigate().to(logoutUrl); - - logoutConfirmPage.assertCurrent(); - logoutConfirmPage.confirmLogout(); - infoPage.assertCurrent(); - - driver.navigate().to(redirectUrl); - } - - void setAdapterAndServerTimeOffset(int timeOffset, String url) { - setTimeOffset(timeOffset); - - String timeOffsetUri = UriBuilder.fromUri(url) - .queryParam("timeOffset", timeOffset) - .build().toString(); - - driver.navigate().to(timeOffsetUri); - WaitUtils.waitUntilElement(By.tagName("body")).is().visible(); - } - - public void createRoles() { - RealmResource realm = realmsResouce().realm(REALM_NAME); - - RoleRepresentation correct = new RoleRepresentation(CORRECT_ROLE, CORRECT_ROLE, false); - realm.roles().create(correct); - } - - public void addUsers() { - addUser(USER_LOGIN, USER_EMAIL, USER_PASSWORD, CORRECT_ROLE); - } - - public void cleanupUsers() { - RealmResource realmResource = adminClient.realm(REALM_NAME); - UserRepresentation userRep = ApiUtil.findUserByUsername(realmResource, USER_LOGIN); - if (userRep != null) { - realmResource.users().get(userRep.getId()).remove(); - } - } - - public void cleanupRoles() { - RealmResource realm = realmsResouce().realm(REALM_NAME); - - RoleResource correctRole = realm.roles().get(CORRECT_ROLE); - correctRole.remove(); - } - - @Before - public void setUp() { - createRoles(); - addUsers(); - } - - @After - public void tearDown() { - cleanupUsers(); - cleanupRoles(); - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/AccountLinkSpringBootTest.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/AccountLinkSpringBootTest.java deleted file mode 100644 index 7311bd1ba62..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/AccountLinkSpringBootTest.java +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright 2023 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 org.keycloak.testsuite.springboot; - -import org.hamcrest.Matchers; -import org.jboss.arquillian.graphene.page.Page; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.Ignore; -import org.keycloak.OAuth2Constants; -import org.keycloak.admin.client.resource.ClientResource; -import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.common.Profile; -import org.keycloak.common.util.Base64Url; -import org.keycloak.models.Constants; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.protocol.oidc.OIDCLoginProtocolService; -import org.keycloak.representations.AccessTokenResponse; -import org.keycloak.representations.idm.*; -import org.keycloak.services.resources.LoginActionsService; -import org.keycloak.testsuite.ActionURIUtils; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.arquillian.AuthServerTestEnricher; -import org.keycloak.testsuite.arquillian.annotation.DisableFeature; -import org.keycloak.testsuite.broker.BrokerTestTools; -import org.keycloak.testsuite.pages.ErrorPage; -import org.keycloak.testsuite.pages.LoginUpdateProfilePage; -import org.keycloak.testsuite.util.OAuthClient; -import org.keycloak.testsuite.util.WaitUtils; -import org.keycloak.util.JsonSerialization; - -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.core.UriBuilder; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.CoreMatchers.startsWith; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT; -import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT_LINKS; -import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient; -import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot; -import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; -import static org.keycloak.testsuite.util.WaitUtils.pause; - -public class AccountLinkSpringBootTest extends AbstractSpringBootTest { - - private static final String PARENT_REALM = "parent-realm"; - - private static final String LINKING_URL = BASE_URL + "/LinkServlet"; - - private static final String PARENT_USERNAME = "parent-username"; - private static final String PARENT_PASSWORD = "parent-password"; - - private static final String CHILD_USERNAME_1 = "child-username-1"; - private static final String CHILD_PASSWORD_1 = "child-password-1"; - - private static final String CHILD_USERNAME_2 = "child-username-2"; - private static final String CHILD_PASSWORD_2 = "child-password-2"; - - @Page - private LinkingPage linkingPage; - - @Page - private LoginUpdateProfilePage loginUpdateProfilePage; - - @Page - private ErrorPage errorPage; - - @Override - public void addTestRealms(List testRealms) { - RealmRepresentation realm = new RealmRepresentation(); - realm.setRealm(REALM_NAME); - realm.setEnabled(true); - realm.setPublicKey(REALM_PUBLIC_KEY); - realm.setPrivateKey(REALM_PRIVATE_KEY); - realm.setAccessTokenLifespan(600); - realm.setAccessCodeLifespan(10); - realm.setAccessCodeLifespanUserAction(6000); - realm.setSslRequired("external"); - ClientRepresentation servlet = new ClientRepresentation(); - servlet.setClientId(CLIENT_ID); - servlet.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); - servlet.setAdminUrl(LINKING_URL); - servlet.setDirectAccessGrantsEnabled(true); - servlet.setBaseUrl(LINKING_URL); - servlet.setRedirectUris(new LinkedList<>()); - servlet.getRedirectUris().add(LINKING_URL + "/*"); - servlet.setSecret(SECRET); - servlet.setFullScopeAllowed(true); - realm.setClients(new LinkedList<>()); - realm.getClients().add(servlet); - testRealms.add(realm); - - realm = new RealmRepresentation(); - realm.setRealm(PARENT_REALM); - realm.setEnabled(true); - - testRealms.add(realm); - } - - @Override - public void addUsers() { - addIdpUser(); - addChildUser(); - } - - @Override - public void cleanupUsers() { - } - - @Override - public void createRoles() { - } - - @Override - protected boolean isImportAfterEachMethod() { - return true; - } - - public void addIdpUser() { - RealmResource realm = adminClient.realms().realm(PARENT_REALM); - UserRepresentation user = new UserRepresentation(); - user.setUsername(PARENT_USERNAME); - user.setEnabled(true); - createUserAndResetPasswordWithAdminClient(realm, user, PARENT_PASSWORD); - } - - private String childUserId = null; - - public void addChildUser() { - RealmResource realm = adminClient.realms().realm(REALM_NAME); - UserRepresentation user = new UserRepresentation(); - user.setUsername(CHILD_USERNAME_1); - user.setEnabled(true); - childUserId = createUserAndResetPasswordWithAdminClient(realm, user, CHILD_PASSWORD_1); - UserRepresentation user2 = new UserRepresentation(); - user2.setUsername(CHILD_USERNAME_2); - user2.setEnabled(true); - String user2Id = createUserAndResetPasswordWithAdminClient(realm, user2, CHILD_PASSWORD_2); - - // have to add a role as undertow default auth manager doesn't like "*". todo we can remove this eventually as undertow fixes this in later versions - realm.roles().create(new RoleRepresentation(CORRECT_ROLE, null, false)); - RoleRepresentation role = realm.roles().get(CORRECT_ROLE).toRepresentation(); - List roles = new LinkedList<>(); - roles.add(role); - realm.users().get(childUserId).roles().realmLevel().add(roles); - realm.users().get(user2Id).roles().realmLevel().add(roles); - ClientRepresentation brokerService = realm.clients().findByClientId(Constants.BROKER_SERVICE_CLIENT_ID).get(0); - role = realm.clients().get(brokerService.getId()).roles().get(Constants.READ_TOKEN_ROLE).toRepresentation(); - roles.clear(); - roles.add(role); - realm.users().get(childUserId).roles().clientLevel(brokerService.getId()).add(roles); - realm.users().get(user2Id).roles().clientLevel(brokerService.getId()).add(roles); - } - - @Before - public void createParentChild() { - BrokerTestTools.createKcOidcBroker(adminClient, REALM_NAME, PARENT_REALM); - - testRealmLoginPage.setAuthRealm(REALM_NAME); - } - - - @Test - public void testErrorConditions() throws Exception { - RealmResource realm = adminClient.realms().realm(REALM_NAME); - List links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - ClientRepresentation client = adminClient.realms().realm(REALM_NAME).clients().findByClientId(CLIENT_ID).get(0); - - UriBuilder redirectUri = UriBuilder.fromUri(LINKING_URL).queryParam("response", "true"); - - UriBuilder directLinking = UriBuilder.fromUri(getAuthServerContextRoot() + "/auth") - .path("realms/{child-realm}/broker/{provider}/link") - .queryParam("client_id", CLIENT_ID) - .queryParam("redirect_uri", redirectUri.build()) - .queryParam("hash", Base64Url.encode("crap".getBytes())) - .queryParam("nonce", UUID.randomUUID().toString()); - - String linkUrl = directLinking - .build(REALM_NAME, PARENT_REALM).toString(); - - // test that child user cannot log into parent realm - navigateTo(linkUrl); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - assertThat(driver.getCurrentUrl(), containsString("link_error=not_logged_in")); - - logoutAll(); - - // now log in - navigateTo(LINKING_URL + "?response=true"); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - - linkingPage.assertIsCurrent(); - - assertThat(linkingPage.getErrorMessage().toLowerCase(), containsString("account linked")); - - // now test CSRF with bad hash. - navigateTo(linkUrl); - - assertThat(driver.getPageSource(), containsString("We are sorry...")); - - logoutAll(); - - // now log in again with client that does not have scope - - String accountId = adminClient.realms().realm(REALM_NAME).clients().findByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).get(0).getId(); - RoleRepresentation manageAccount = adminClient.realms().realm(REALM_NAME).clients().get(accountId).roles().get(MANAGE_ACCOUNT).toRepresentation(); - RoleRepresentation manageLinks = adminClient.realms().realm(REALM_NAME).clients().get(accountId).roles().get(MANAGE_ACCOUNT_LINKS).toRepresentation(); - RoleRepresentation userRole = adminClient.realms().realm(REALM_NAME).roles().get(CORRECT_ROLE).toRepresentation(); - - client.setFullScopeAllowed(false); - ClientResource clientResource = adminClient.realms().realm(REALM_NAME).clients().get(client.getId()); - clientResource.update(client); - - List roles = new LinkedList<>(); - roles.add(userRole); - clientResource.getScopeMappings().realmLevel().add(roles); - - navigateTo(LINKING_URL + "?response=true"); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - - linkingPage.assertIsCurrent(); - assertThat(linkingPage.getErrorMessage().toLowerCase(), containsString("account linked")); - - UriBuilder linkBuilder = UriBuilder.fromUri(LINKING_URL); - String clientLinkUrl = linkBuilder.clone() - .queryParam("realm", REALM_NAME) - .queryParam("provider", PARENT_REALM).build().toString(); - - navigateTo(clientLinkUrl); - assertThat(driver.getCurrentUrl(), containsString("error=not_allowed")); - - logoutAll(); - - // add MANAGE_ACCOUNT_LINKS scope should pass. - - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - roles = new LinkedList<>(); - roles.add(manageLinks); - clientResource.getScopeMappings().clientLevel(accountId).add(roles); - - navigateTo(clientLinkUrl); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - - testRealmLoginPage.setAuthRealm(PARENT_REALM); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(PARENT_USERNAME, PARENT_PASSWORD); - - testRealmLoginPage.setAuthRealm(REALM_NAME); // clean - - assertThat(driver.getCurrentUrl(), startsWith(linkBuilder.toTemplate())); - assertThat(driver.getPageSource(), containsString("Account linked")); - - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(not(empty()))); - - realm.users().get(childUserId).removeFederatedIdentity(PARENT_REALM); - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - clientResource.getScopeMappings().clientLevel(accountId).remove(roles); - - logoutAll(); - - navigateTo(clientLinkUrl); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - - assertThat(driver.getCurrentUrl(), containsString("link_error=not_allowed")); - - logoutAll(); - - // add MANAGE_ACCOUNT scope should pass - - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - roles = new LinkedList<>(); - roles.add(manageAccount); - clientResource.getScopeMappings().clientLevel(accountId).add(roles); - - navigateTo(clientLinkUrl); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - - testRealmLoginPage.setAuthRealm(PARENT_REALM); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(PARENT_USERNAME, PARENT_PASSWORD); - - testRealmLoginPage.setAuthRealm(REALM_NAME); // clean - - - assertThat(driver.getCurrentUrl(), startsWith(linkBuilder.toTemplate())); - assertThat(driver.getPageSource(), containsString("Account linked")); - - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(not(empty()))); - - realm.users().get(childUserId).removeFederatedIdentity(PARENT_REALM); - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - clientResource.getScopeMappings().clientLevel(accountId).remove(roles); - - logoutAll(); - - navigateTo(clientLinkUrl); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - - assertThat(driver.getCurrentUrl(), containsString("link_error=not_allowed")); - - logoutAll(); - - // undo fullScopeAllowed - - client = adminClient.realms().realm(REALM_NAME).clients().findByClientId(CLIENT_ID).get(0); - client.setFullScopeAllowed(true); - clientResource.update(client); - - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - logoutAll(); - } - - @Test - public void testAccountLink() throws Exception { - RealmResource realm = adminClient.realms().realm(REALM_NAME); - List links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - UriBuilder linkBuilder = UriBuilder.fromUri(LINKING_URL); - String linkUrl = linkBuilder.clone() - .queryParam("realm", REALM_NAME) - .queryParam("provider", PARENT_REALM).build().toString(); - log.info("linkUrl: " + linkUrl); - navigateTo(linkUrl); - assertCurrentUrlStartsWith(testRealmLoginPage); - - assertThat(driver.getPageSource(), containsString(PARENT_REALM)); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - - testRealmLoginPage.setAuthRealm(PARENT_REALM); - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(PARENT_USERNAME, PARENT_PASSWORD); - testRealmLoginPage.setAuthRealm(REALM_NAME); // clean - - log.info("After linking: " + driver.getCurrentUrl()); - log.info(driver.getPageSource()); - - assertThat(driver.getCurrentUrl(), startsWith(linkBuilder.toTemplate())); - assertThat(driver.getPageSource(), containsString("Account linked")); - - OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest( - REALM_NAME, - CHILD_USERNAME_1, - CHILD_PASSWORD_1, - null, - CLIENT_ID, - SECRET); - - assertThat(response.getAccessToken(), is(notNullValue())); - assertThat(response.getError(), is(nullValue())); - - - Client httpClient = ClientBuilder.newClient(); - String firstToken = getToken(response, httpClient); - assertThat(firstToken, is(notNullValue())); - - navigateTo(linkUrl); - assertThat(driver.getPageSource(), containsString("Account linked")); - - String nextToken = getToken(response, httpClient); - assertThat(nextToken, is(notNullValue())); - assertThat(firstToken, is(not(equalTo(nextToken)))); - - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(not(empty()))); - - realm.users().get(childUserId).removeFederatedIdentity(PARENT_REALM); - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - logoutAll(); - } - - @Test - public void testLinkOnlyProvider() throws Exception { - RealmResource realm = adminClient.realms().realm(REALM_NAME); - IdentityProviderRepresentation rep = realm.identityProviders().get(PARENT_REALM).toRepresentation(); - rep.setLinkOnly(true); - realm.identityProviders().get(PARENT_REALM).update(rep); - - try { - List links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - UriBuilder linkBuilder = UriBuilder.fromUri(LINKING_URL); - String linkUrl = linkBuilder.clone() - .queryParam("realm", REALM_NAME) - .queryParam("provider", PARENT_REALM).build().toString(); - navigateTo(linkUrl); - assertCurrentUrlStartsWith(testRealmLoginPage); - - // should not be on login page. This is what we are testing - assertThat(driver.getPageSource(), not(containsString(PARENT_REALM))); - - // now test that we can still link. - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - - testRealmLoginPage.setAuthRealm(PARENT_REALM); - assertCurrentUrlStartsWith(testRealmLoginPage); - - testRealmLoginPage.form().login(PARENT_USERNAME, PARENT_PASSWORD); - testRealmLoginPage.setAuthRealm(REALM_NAME); - - log.info("After linking: " + driver.getCurrentUrl()); - log.info(driver.getPageSource()); - - assertThat(driver.getCurrentUrl(), startsWith(linkBuilder.toTemplate())); - assertThat(driver.getPageSource(), containsString("Account linked")); - - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(not(empty()))); - - realm.users().get(childUserId).removeFederatedIdentity(PARENT_REALM); - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - pause(500); - - logoutAll(); - - log.info("testing link-only attack"); - - navigateTo(linkUrl); - assertCurrentUrlStartsWith(testRealmLoginPage); - - log.info("login page uri is: " + driver.getCurrentUrl()); - - // ok, now scrape the code from page - String pageSource = driver.getPageSource(); - String action = ActionURIUtils.getActionURIFromPageSource(pageSource); - System.out.println("action uri: " + action); - - Map queryParams = ActionURIUtils.parseQueryParamsFromActionURI(action); - System.out.println("query params: " + queryParams); - - // now try and use the code to login to remote link-only idp - - String uri = "/auth/realms/" + REALM_NAME + "/broker/" + PARENT_REALM + "/login"; - - uri = UriBuilder.fromUri(getAuthServerContextRoot()) - .path(uri) - .queryParam(LoginActionsService.SESSION_CODE, queryParams.get(LoginActionsService.SESSION_CODE)) - .queryParam(Constants.CLIENT_ID, queryParams.get(Constants.CLIENT_ID)) - .queryParam(Constants.TAB_ID, queryParams.get(Constants.TAB_ID)) - .build().toString(); - - log.info("hack uri: " + uri); - - navigateTo(uri); - - assertThat(driver.getPageSource(), containsString("Could not send authentication request to identity provider.")); - } finally { - rep.setLinkOnly(false); - realm.identityProviders().get(PARENT_REALM).update(rep); - } - } - - @Test - @Ignore - public void testAccountLinkingExpired() throws Exception { - RealmResource realm = adminClient.realms().realm(REALM_NAME); - List links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - // Login to account mgmt first - //profilePage.open(REALM_NAME); - WaitUtils.waitForPageToLoad(); - - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(CHILD_USERNAME_1, CHILD_PASSWORD_1); - //profilePage.assertCurrent(); - - // Now in another tab, request account linking - UriBuilder linkBuilder = UriBuilder.fromUri(LINKING_URL); - String linkUrl = linkBuilder.clone() - .queryParam("realm", REALM_NAME) - .queryParam("provider", PARENT_REALM).build().toString(); - navigateTo(linkUrl); - - testRealmLoginPage.setAuthRealm(PARENT_REALM); - assertCurrentUrlStartsWith(testRealmLoginPage); - - setTimeOffset(1); // We need to "wait" for 1 second so that notBeforePolicy invalidates token created when logging to child realm - - // Logout "child" userSession in the meantime (for example through admin request) - realm.logoutAll(); - - // Finish login on parent. - testRealmLoginPage.form().login(PARENT_USERNAME, PARENT_PASSWORD); - - - // Test I was not automatically linked - links = realm.users().get(childUserId).getFederatedIdentity(); - assertThat(links, is(empty())); - - errorPage.assertCurrent(); - assertThat(errorPage.getError(), is(equalTo("Requested broker account linking, but current session is no longer valid."))); - - logoutAll(); - - navigateTo(linkUrl); // Check we are logged out - - testRealmLoginPage.setAuthRealm(REALM_NAME); - assertCurrentUrlStartsWith(testRealmLoginPage); - - resetTimeOffset(); - } - - private void navigateTo(String uri) { - driver.navigate().to(uri); - WaitUtils.waitForPageToLoad(); - } - - public void logoutAll() { - adminClient.realm(REALM_NAME).logoutAll(); - adminClient.realm(PARENT_REALM).logoutAll(); - } - - private String getToken(OAuthClient.AccessTokenResponse response, Client httpClient) throws Exception { - log.info("target here is " + OAuthClient.AUTH_SERVER_ROOT); - String idpToken = httpClient.target(OAuthClient.AUTH_SERVER_ROOT) - .path("realms") - .path(REALM_NAME) - .path("broker") - .path(PARENT_REALM) - .path("token") - .request() - .header("Authorization", "Bearer " + response.getAccessToken()) - .get(String.class); - AccessTokenResponse res = JsonSerialization.readValue(idpToken, AccessTokenResponse.class); - return res.getToken(); - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/BasicSpringBootTest.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/BasicSpringBootTest.java deleted file mode 100644 index 887c422a1f7..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/BasicSpringBootTest.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.keycloak.admin.client.resource.RolesResource; -import org.keycloak.representations.idm.RoleRepresentation; -import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.testsuite.admin.ApiUtil; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; -import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad; - -public class BasicSpringBootTest extends AbstractSpringBootTest { - - private static final String USER_LOGIN_2 = "testuser2"; - private static final String USER_EMAIL_2 = "user2@email.test"; - private static final String USER_PASSWORD_2 = "user2-password"; - - private static final String INCORRECT_ROLE = "wrong-admin"; - - @Before - public void addIncorrectUser() { - RolesResource rolesResource = adminClient.realm(REALM_NAME).roles(); - - RoleRepresentation role = new RoleRepresentation(INCORRECT_ROLE, INCORRECT_ROLE, false); - - rolesResource.create(role); - - addUser(USER_LOGIN_2, USER_EMAIL_2, USER_PASSWORD_2, INCORRECT_ROLE); - - testRealmLoginPage.setAuthRealm(REALM_NAME); - } - - @After - public void removeUser() { - UserRepresentation user = ApiUtil.findUserByUsername(adminClient.realm(REALM_NAME), USER_LOGIN_2); - - if (user != null) { - adminClient.realm(REALM_NAME).users().delete(user.getId()); - } - - adminClient.realm(REALM_NAME).roles().deleteRole(INCORRECT_ROLE); - } - - private void navigateToApplication() { - driver.navigate().to(APPLICATION_URL + "/index.html"); - waitForPageToLoad(); - } - - @Test - public void testCorrectUser() { - navigateToApplication(); - - applicationPage.assertIsCurrent(); - applicationPage.goAdmin(); - - assertCurrentUrlStartsWith(testRealmLoginPage); - - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - - adminPage.assertIsCurrent(); - assertThat(driver.getPageSource(), containsString("You are now admin")); - - logout(BASE_URL); - waitForPageToLoad(); - - assertCurrentUrlStartsWith(testRealmLoginPage); - - } - - @Test - public void testIncorrectUser() { - navigateToApplication(); - - applicationPage.assertIsCurrent(); - applicationPage.goAdmin(); - - assertCurrentUrlStartsWith(testRealmLoginPage); - - testRealmLoginPage.form().login(USER_LOGIN_2, USER_PASSWORD_2); - - assertThat(driver.getPageSource(), containsString("Forbidden")); - - logout(BASE_URL); - waitForPageToLoad(); - } - - @Test - public void testIncorrectCredentials() { - navigateToApplication(); - - applicationPage.assertIsCurrent(); - applicationPage.goAdmin(); - - assertCurrentUrlStartsWith(testRealmLoginPage); - - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD_2); - - assertThat(testRealmLoginPage.feedbackMessage().isError(), is(true)); - assertThat(testRealmLoginPage.feedbackMessage().getText(), is(equalTo("Invalid username or password."))); - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/OfflineTokenSpringBootTest.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/OfflineTokenSpringBootTest.java deleted file mode 100644 index 9a4837bcca2..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/OfflineTokenSpringBootTest.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import org.eclipse.persistence.annotations.BatchFetch; -import org.jboss.arquillian.graphene.page.Page; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.OAuth2Constants; -import org.keycloak.common.Profile; -import org.keycloak.events.Details; -import org.keycloak.events.EventType; -import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.services.Urls; -import org.keycloak.testsuite.AssertEvents; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.arquillian.annotation.DisableFeature; -import org.keycloak.testsuite.pages.OAuthGrantPage; -import org.keycloak.testsuite.util.ClientManager; -import org.keycloak.testsuite.util.WaitUtils; -import org.keycloak.testsuite.util.AccountHelper; -import org.keycloak.util.TokenUtil; -import org.openqa.selenium.By; - -import javax.ws.rs.core.UriBuilder; -import java.util.List; -import java.util.Map; -import java.util.LinkedHashMap; -import java.util.ArrayList; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; -import static org.keycloak.testsuite.util.WaitUtils.pause; -import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad; - -public class OfflineTokenSpringBootTest extends AbstractSpringBootTest { - private static final String SERVLET_URL = BASE_URL + "/TokenServlet"; - private final String TEST_REALM = "test"; - - @Rule - public AssertEvents events = new AssertEvents(this); - - @Page - private OAuthGrantPage oauthGrantPage; - - @Before - public void setUpAuthRealm() { - testRealmLoginPage.setAuthRealm(REALM_NAME); - } - - @Test - public void testTokens() { - String servletUri = UriBuilder.fromUri(SERVLET_URL) - .queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS) - .build().toString(); - driver.navigate().to(servletUri); - waitForPageToLoad(); - - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - - tokenPage.assertIsCurrent(); - - assertThat(tokenPage.getRefreshToken().getType(), is(equalTo(TokenUtil.TOKEN_TYPE_OFFLINE))); - assertThat(tokenPage.getRefreshToken().getExpiration(), is(equalTo(0))); - - String accessTokenId = tokenPage.getAccessToken().getId(); - String refreshTokenId = tokenPage.getRefreshToken().getId(); - - setAdapterAndServerTimeOffset(19999, SERVLET_URL); - - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - tokenPage.assertIsCurrent(); - assertThat(tokenPage.getRefreshToken().getId(), is(not(equalTo(refreshTokenId)))); - assertThat(tokenPage.getAccessToken().getId(), is(not(equalTo(accessTokenId)))); - - setAdapterAndServerTimeOffset(0, SERVLET_URL); - - logout(SERVLET_URL); - waitForPageToLoad(); - assertCurrentUrlStartsWith(testRealmLoginPage); - } - - @Test - public void testRevoke() { - // Login to servlet first with offline token - String servletUri = UriBuilder.fromUri(SERVLET_URL) - .queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS) - .build().toString(); - driver.navigate().to(servletUri); - waitForPageToLoad(); - - assertCurrentUrlStartsWith(testRealmLoginPage); - - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - tokenPage.assertIsCurrent(); - - assertThat(tokenPage.getRefreshToken().getType(), is(equalTo(TokenUtil.TOKEN_TYPE_OFFLINE))); - - // Assert refresh works with increased time - setAdapterAndServerTimeOffset(9999, SERVLET_URL); - - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - tokenPage.assertIsCurrent(); - - setAdapterAndServerTimeOffset(0, SERVLET_URL); - - events.clear(); - - // Go to account service and revoke grant - List> userConsents = AccountHelper.getUserConsents(adminClient.realm(TEST_REALM), USER_LOGIN); - String grantValue = String.valueOf(((LinkedHashMap) ((ArrayList) userConsents.get(0).get("additionalGrants")).get(0)).get("key")); - assertThat(userConsents, hasSize(1)); - Assert.assertEquals("Offline Token", grantValue); - - AccountHelper.revokeConsents(adminClient.realm(TEST_REALM), USER_LOGIN, CLIENT_ID); - userConsents = AccountHelper.getUserConsents(adminClient.realm(TEST_REALM), USER_LOGIN); - Assert.assertEquals(userConsents.size(), 0); - - UserRepresentation userRepresentation = - ApiUtil.findUserByUsername(realmsResouce().realm(REALM_NAME), USER_LOGIN); - assertThat(userRepresentation, is(notNullValue())); - - // Assert refresh doesn't work now (increase time one more time) - setAdapterAndServerTimeOffset(19999, SERVLET_URL); - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - assertCurrentUrlStartsWith(testRealmLoginPage); - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - tokenPage.assertIsCurrent(); - - setAdapterAndServerTimeOffset(0, SERVLET_URL); - logout(SERVLET_URL); - } - - @Test - public void testConsent() { - ClientManager.realm(adminClient.realm(REALM_NAME)).clientId(CLIENT_ID).consentRequired(true); - - // Assert grant page doesn't have 'Offline Access' role when offline token is not requested - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - oauthGrantPage.assertCurrent(); - oauthGrantPage.cancel(); - - driver.navigate().to(UriBuilder.fromUri(SERVLET_URL) - .queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS) - .build().toString()); - waitForPageToLoad(); - - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - oauthGrantPage.assertCurrent(); - oauthGrantPage.accept(); - - tokenPage.assertIsCurrent(); - assertThat(tokenPage.getRefreshToken().getType(), is(equalTo(TokenUtil.TOKEN_TYPE_OFFLINE))); - - List> userConsents = AccountHelper.getUserConsents(adminClient.realm(TEST_REALM), USER_LOGIN); - String grantValue = String.valueOf(((LinkedHashMap) ((ArrayList) userConsents.get(0).get("additionalGrants")).get(0)).get("key")); - Assert.assertTrue(((List) userConsents.get(0).get("grantedClientScopes")).stream().anyMatch(p -> p.equals("offline_access"))); - Assert.assertEquals("Offline Token", grantValue); - - //This was necessary to be introduced, otherwise other testcases will fail - logout(SERVLET_URL); - assertCurrentUrlStartsWith(testRealmLoginPage); - - events.clear(); - - // Revert change - ClientManager.realm(adminClient.realm(REALM_NAME)).clientId(CLIENT_ID).consentRequired(false); - } -} diff --git a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/SessionSpringBootTest.java b/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/SessionSpringBootTest.java deleted file mode 100644 index 3173809f1df..00000000000 --- a/testsuite/integration-arquillian/tests/other/springboot-tests/src/test/java/org/keycloak/testsuite/springboot/SessionSpringBootTest.java +++ /dev/null @@ -1,225 +0,0 @@ -package org.keycloak.testsuite.springboot; - -import org.jboss.arquillian.drone.api.annotation.Drone; -import org.jboss.arquillian.graphene.page.Page; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.keycloak.admin.client.resource.ClientResource; -import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.common.Profile; -import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.testsuite.Assert; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.arquillian.annotation.DisableFeature; -import org.keycloak.testsuite.auth.page.login.OIDCLogin; -import org.keycloak.testsuite.pages.InfoPage; -import org.keycloak.testsuite.pages.LogoutConfirmPage; -import org.keycloak.testsuite.util.DroneUtils; -import org.keycloak.testsuite.util.SecondBrowser; -import org.keycloak.testsuite.util.WaitUtils; -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; -import static org.keycloak.testsuite.util.WaitUtils.pause; -import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad; - -public class SessionSpringBootTest extends AbstractSpringBootTest { - - private static final String SERVLET_URL = BASE_URL + "/SessionServlet"; - - static final String USER_LOGIN_CORRECT_2 = "testcorrectuser2"; - static final String USER_EMAIL_CORRECT_2 = "usercorrect2@email.test"; - static final String USER_PASSWORD_CORRECT_2 = "testcorrectpassword2"; - - @Page - private SessionPage sessionPage; - - @Page - @SecondBrowser - private SessionPage secondBrowserSessionPage; - - @Drone - @SecondBrowser - private WebDriver driver2; - - @Page - @SecondBrowser - private OIDCLogin secondTestRealmLoginPage; - - @Page - @SecondBrowser - protected LogoutConfirmPage secondBrowserLogoutConfirmPage; - - @Page - @SecondBrowser - protected InfoPage secondBrowserInfoPage; - - - @Override - public void setDefaultPageUriParameters() { - super.setDefaultPageUriParameters(); - testRealmLoginPage.setAuthRealm(REALM_NAME); - secondTestRealmLoginPage.setAuthRealm(REALM_NAME); - } - - private void loginAndCheckSession() { - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - assertCurrentUrlStartsWith(testRealmLoginPage, driver); - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - - sessionPage.assertIsCurrent(); - assertThat(sessionPage.getCounter(), is(equalTo(0))); - - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - assertThat(sessionPage.getCounter(), is(equalTo(1))); - } - - @Before - public void addUserCorrect2() { - addUser(USER_LOGIN_CORRECT_2, USER_EMAIL_CORRECT_2, USER_PASSWORD_CORRECT_2, CORRECT_ROLE); - } - - @After - public void removeUserCorrect2() { - UserRepresentation userRep = ApiUtil.findUserByUsername(realmsResouce().realm(REALM_NAME), USER_LOGIN_CORRECT_2); - if (userRep != null) { - realmsResouce().realm(REALM_NAME).users().get(userRep.getId()).remove(); - } - } - - @Test - public void testSingleSessionInvalidated() { - loginAndCheckSession(); - - DroneUtils.addWebDriver(driver2); - - driver2.navigate().to(SERVLET_URL); - waitForPageToLoad(); // driver2 will be used because of DroneUtils.addWebDriver() - - log.info("current title is " + driver2.getTitle()); - assertCurrentUrlStartsWith(secondTestRealmLoginPage, driver2); - secondTestRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - - secondBrowserSessionPage.assertIsCurrent(); - - assertThat(secondBrowserSessionPage.getCounter(), is(equalTo(0))); - - // Counter increased now - driver2.navigate().to(SERVLET_URL); - waitForPageToLoad(); // driver2 will be used because of DroneUtils.addWebDriver() - - assertThat(secondBrowserSessionPage.getCounter(), is(equalTo(1))); - - DroneUtils.removeWebDriver(); // From now driver will be used instead of driver2 - - // Logout in browser1 - logout(SERVLET_URL); - waitForPageToLoad(); - - // Assert that I am logged out in browser1 - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - assertCurrentUrlStartsWith(testRealmLoginPage, driver); - - // Assert that I am still logged in browser2 and same session is still preserved - DroneUtils.addWebDriver(driver2); - driver2.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - secondBrowserSessionPage.assertIsCurrent(); - assertThat(secondBrowserSessionPage.getCounter(), is(equalTo(2))); - - String logoutUrl = getLogoutUrl(); - driver2.navigate().to(logoutUrl); - - waitForPageToLoad(); - assertThat(true, is(secondBrowserLogoutConfirmPage.isCurrent(driver2))); - secondBrowserLogoutConfirmPage.confirmLogout(driver2); - waitForPageToLoad(); - secondBrowserInfoPage.assertCurrent(); - waitForPageToLoad(); - driver2.navigate().to(SERVLET_URL); - - waitForPageToLoad(); - assertCurrentUrlStartsWith(secondTestRealmLoginPage, driver2); - - DroneUtils.removeWebDriver(); - } - - @Test - public void testSessionInvalidatedAfterFailedRefresh() { - RealmResource realmResource = adminClient.realm(REALM_NAME); - RealmRepresentation realmRep = realmResource.toRepresentation(); - ClientResource clientResource = null; - for (ClientRepresentation clientRep : realmResource.clients().findAll()) { - if (CLIENT_ID.equals(clientRep.getClientId())) { - clientResource = realmResource.clients().get(clientRep.getId()); - } - } - - assertThat(clientResource, is(notNullValue())); - - clientResource.toRepresentation().setAdminUrl(""); - int origTokenLifespan = realmRep.getAccessCodeLifespan(); - realmRep.setAccessCodeLifespan(1); - realmResource.update(realmRep); - - // Login - loginAndCheckSession(); - - // Logout - logout(SERVLET_URL); - waitForPageToLoad(); - - // Assert that http session was invalidated - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - assertCurrentUrlStartsWith(testRealmLoginPage, driver); - testRealmLoginPage.form().login(USER_LOGIN, USER_PASSWORD); - - sessionPage.assertIsCurrent(); - assertThat(sessionPage.getCounter(), is(equalTo(0))); - - clientResource.toRepresentation().setAdminUrl(BASE_URL); - realmRep.setAccessCodeLifespan(origTokenLifespan); - realmResource.update(realmRep); - - logout(SERVLET_URL); - waitForPageToLoad(); - } - - @Test - public void testAdminApplicationLogout() { - loginAndCheckSession(); - - // logout user2 with admin client - UserRepresentation correct2 = realmsResouce().realm(REALM_NAME) - .users().search(USER_LOGIN_CORRECT_2, null, null, null, null, null).get(0); - realmsResouce().realm(REALM_NAME).users().get(correct2.getId()).logout(); - - // user1 should be still logged with original httpSession in our browser window - driver.navigate().to(SERVLET_URL); - waitForPageToLoad(); - - sessionPage.assertIsCurrent(); - assertThat(sessionPage.getCounter(), is(equalTo(2))); - - logout(SERVLET_URL); - waitForPageToLoad(); - } -}