diff --git a/adapters/saml/undertow/src/main/resources/META-INF/services/io.undertow.servlet.ServletExtension b/adapters/saml/undertow/src/main/resources/META-INF/services/io.undertow.servlet.ServletExtension new file mode 100644 index 0000000000..f385fd0328 --- /dev/null +++ b/adapters/saml/undertow/src/main/resources/META-INF/services/io.undertow.servlet.ServletExtension @@ -0,0 +1,18 @@ +# +# 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. +# + +org.keycloak.adapters.saml.undertow.SamlServletExtension diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index db661793d9..1c7bcf398c 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -1086,7 +1086,7 @@ public class RepresentationToModel { * @return */ public static ClientModel createClient(KeycloakSession session, RealmModel realm, ClientRepresentation resourceRep, boolean addDefaultRoles) { - logger.debug("Create client: {0}" + resourceRep.getClientId()); + logger.debugv("Create client: {0}", resourceRep.getClientId()); ClientModel client = resourceRep.getId() != null ? realm.addClient(resourceRep.getId(), resourceRep.getClientId()) : realm.addClient(resourceRep.getClientId()); if (resourceRep.getName() != null) client.setName(resourceRep.getName()); diff --git a/testsuite/integration-arquillian/servers/app-server/undertow/pom.xml b/testsuite/integration-arquillian/servers/app-server/undertow/pom.xml index c54e7e9484..39ba1c8a83 100644 --- a/testsuite/integration-arquillian/servers/app-server/undertow/pom.xml +++ b/testsuite/integration-arquillian/servers/app-server/undertow/pom.xml @@ -32,6 +32,10 @@ org.keycloak keycloak-undertow-adapter + + org.keycloak + keycloak-saml-undertow-adapter + org.keycloak.testsuite integration-arquillian-servers-app-server-spi diff --git a/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/UndertowAppServer.java b/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/UndertowAppServer.java index 81f99809dc..01a4a08c25 100644 --- a/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/UndertowAppServer.java +++ b/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/UndertowAppServer.java @@ -27,12 +27,18 @@ import io.undertow.servlet.api.ServletInfo; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; +import java.nio.charset.Charset; import java.util.Collection; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import javax.servlet.ServletException; +import javax.ws.rs.Path; +import javax.ws.rs.core.Application; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import org.arquillian.undertow.UndertowContainerConfiguration; import org.jboss.arquillian.container.spi.client.container.DeployableContainer; import org.jboss.arquillian.container.spi.client.container.DeploymentException; @@ -43,11 +49,14 @@ import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaD import org.jboss.arquillian.container.spi.client.protocol.metadata.Servlet; import org.jboss.logging.Logger; import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer; +import org.jboss.resteasy.spi.ResteasyDeployment; import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.asset.ClassAsset; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.shrinkwrap.descriptor.api.Descriptor; import org.jboss.shrinkwrap.undertow.api.UndertowWebArchive; import org.keycloak.common.util.reflections.Reflections; +import org.keycloak.testsuite.arquillian.undertow.saml.util.RestSamlApplicationConfig; import org.keycloak.testsuite.utils.undertow.UndertowDeployerHelper; import org.keycloak.testsuite.utils.undertow.UndertowWarClassLoader; @@ -115,7 +124,13 @@ public class UndertowAppServer implements DeployableContainer> classes = webArchive.getContent(archivePath -> + archivePath.get().startsWith("/WEB-INF/classes/") && + archivePath.get().endsWith(".class") + ).values().stream() + .filter(node -> node.getAsset() instanceof ClassAsset) + .map(node -> ((ClassAsset)node.getAsset()).getSource()) + .filter(clazz -> clazz.isAnnotationPresent(Path.class)) + .collect(Collectors.toSet()); + + ResteasyDeployment deployment = new ResteasyDeployment(); + deployment.setApplication(new RestSamlApplicationConfig(classes)); + return deployment; + } } diff --git a/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/container/UndertowDeploymentArchiveProcessor.java b/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/container/UndertowDeploymentArchiveProcessor.java index dd8e8e2195..6b0ecf4ca1 100644 --- a/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/container/UndertowDeploymentArchiveProcessor.java +++ b/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/container/UndertowDeploymentArchiveProcessor.java @@ -39,6 +39,10 @@ public class UndertowDeploymentArchiveProcessor implements ApplicationArchivePro modifyWebXML(archive, testClass); modifyOIDCAdapterConfig(archive, DeploymentArchiveProcessorUtils.ADAPTER_CONFIG_PATH); + + modifySAMLAdapterConfig(archive, DeploymentArchiveProcessorUtils.SAML_ADAPTER_CONFIG_PATH); + modifySAMLAdapterConfig(archive, DeploymentArchiveProcessorUtils.SAML_ADAPTER_CONFIG_PATH_TENANT1); + modifySAMLAdapterConfig(archive, DeploymentArchiveProcessorUtils.SAML_ADAPTER_CONFIG_PATH_TENANT2); } private void modifyWebXML(Archive archive, TestClass testClass) { @@ -56,4 +60,11 @@ public class UndertowDeploymentArchiveProcessor implements ApplicationArchivePro DeploymentArchiveProcessorUtils.modifyOIDCAdapterConfig(archive, adapterConfigPath); } + + private void modifySAMLAdapterConfig(Archive archive, String adapterConfigPath) { + if (!archive.contains(adapterConfigPath)) return; + + log.debug("Modifying adapter config " + adapterConfigPath + " in " + archive.getName()); + DeploymentArchiveProcessorUtils.modifySAMLAdapterConfig(archive, adapterConfigPath); + } } diff --git a/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/saml/util/RestSamlApplicationConfig.java b/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/saml/util/RestSamlApplicationConfig.java new file mode 100644 index 0000000000..1f9084a2e3 --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/saml/util/RestSamlApplicationConfig.java @@ -0,0 +1,47 @@ +/* + * 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.testsuite.arquillian.undertow.saml.util; + +import java.util.Set; +import javax.ws.rs.core.Application; + +/** + * Wildfly JAX-RS Integration has support for scanning deployment for annotations. + * + * https://github.com/wildfly/wildfly/blob/14.0.1.Final/jaxrs/src/main/java/org/jboss/as/jaxrs/deployment/JaxrsAnnotationProcessor.java + * + * On undertow we have to set Application Class manually: + * + * ResteasyDeployment deployment = new ResteasyDeployment(); + * deployment.setApplication(application); + * + * @author vramik + */ +public class RestSamlApplicationConfig extends Application { + + private final Set> classes; + + public RestSamlApplicationConfig(Set> classes) { + this.classes = classes; + } + + @Override + public Set> getClasses() { + return classes; + } +} diff --git a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/SamlMultiTenantResolver.java b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/SamlMultiTenantResolver.java index 559a4ef3a8..47cc83c55d 100644 --- a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/SamlMultiTenantResolver.java +++ b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/SamlMultiTenantResolver.java @@ -38,7 +38,7 @@ public class SamlMultiTenantResolver implements SamlConfigResolver { throw new IllegalStateException("Not able to resolve realm from the request path!"); } - InputStream is = getClass().getResourceAsStream("/" + realm + "-keycloak-saml.xml"); + InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/" + realm + "-keycloak-saml.xml"); if (is == null) { throw new IllegalStateException("Not able to find the file /" + realm + "-keycloak-saml.xml"); } @@ -46,10 +46,10 @@ public class SamlMultiTenantResolver implements SamlConfigResolver { ResourceLoader loader = new ResourceLoader() { @Override public InputStream getResourceAsStream(String path) { - return getClass().getResourceAsStream(path); + return Thread.currentThread().getContextClassLoader().getResourceAsStream(path); } }; - + try { return new DeploymentBuilder().build(is, loader); } catch (ParsingException e) { diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant1Saml.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant1Saml.java index bb08f88284..9965c57da9 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant1Saml.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant1Saml.java @@ -45,7 +45,7 @@ public class MultiTenant1Saml extends SAMLServlet { @Override public void logout() { - driver.navigate().to(getUriBuilder().queryParam("GLO", "true").queryParam("realm", "tenant1").build().toASCIIString()); + driver.navigate().to(getUriBuilder().clone().queryParam("GLO", "true").queryParam("realm", "tenant1").build().toASCIIString()); getUriBuilder().replaceQueryParam("GLO"); pause(300); } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant2Saml.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant2Saml.java index e2623d1d21..1d81d6cf73 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant2Saml.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant2Saml.java @@ -45,7 +45,7 @@ public class MultiTenant2Saml extends SAMLServlet { @Override public void logout() { - driver.navigate().to(getUriBuilder().queryParam("GLO", "true").queryParam("realm", "tenant2").build().toASCIIString()); + driver.navigate().to(getUriBuilder().clone().queryParam("GLO", "true").queryParam("realm", "tenant2").build().toASCIIString()); getUriBuilder().replaceQueryParam("GLO"); pause(300); } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java index 2f226b929b..0714303986 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java @@ -17,9 +17,12 @@ package org.keycloak.testsuite.adapter.page; +import javax.ws.rs.core.UriBuilder; import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl; +import org.keycloak.testsuite.util.WaitUtils; import static org.keycloak.testsuite.util.WaitUtils.pause; +import org.openqa.selenium.By; /** * @author mhajas @@ -27,8 +30,7 @@ import static org.keycloak.testsuite.util.WaitUtils.pause; public abstract class SAMLServlet extends AbstractPageWithInjectedUrl { public void logout() { - driver.navigate().to(getUriBuilder().queryParam("GLO", "true").build().toASCIIString()); - getUriBuilder().replaceQueryParam("GLO"); + driver.navigate().to(getUriBuilder().clone().queryParam("GLO", "true").build().toASCIIString()); pause(300); } @@ -41,7 +43,14 @@ public abstract class SAMLServlet extends AbstractPageWithInjectedUrl { } public void checkRolesEndPoint(boolean value) { - driver.navigate().to(getUriBuilder().build().toASCIIString() + "/" + (value ? "" : "un") + "checkRoles"); + driver.navigate().to(getUriBuilder().clone().path((value ? "" : "un") + "checkRoles").build().toASCIIString()); pause(300); } + + public void setRolesToCheck(String roles) { + UriBuilder uriBuilder = getUriBuilder().clone(); + String toASCIIString = uriBuilder.path("setCheckRoles").queryParam("roles", roles).build().toASCIIString(); + driver.navigate().to(toASCIIString); + WaitUtils.waitUntilElement(By.tagName("body")).text().contains("These roles will be checked:"); + } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AdapterTestExecutionDecider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AdapterTestExecutionDecider.java index 84b9f17704..1ecb54233d 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AdapterTestExecutionDecider.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AdapterTestExecutionDecider.java @@ -53,7 +53,11 @@ public class AdapterTestExecutionDecider implements TestExecutionDecider { if (testContext.isAdapterContainerEnabled() || testContext.isAdapterContainerEnabledCluster()) { if (method.isAnnotationPresent(AppServerContainer.class)) { // taking method level annotation first as it has higher priority - if (getCorrespondingAnnotation(method).skip()) { + if (getCorrespondingAnnotation(method) == null) { //no corresponding annotation - taking class level annotation + if (getCorrespondingAnnotation(testContext.getTestClass()).skip()) { + return execute(method, Boolean.FALSE, "Skipped by @AppServerContainer class level annotation."); + } + } else if (getCorrespondingAnnotation(method).skip()) { //corresponding annotation return execute(method, Boolean.FALSE, "Skipped by @AppServerContainer method level annotation."); } } else { //taking class level annotation @@ -88,7 +92,7 @@ public class AdapterTestExecutionDecider implements TestExecutionDecider { return appServerContainers.stream() .filter(annotation -> annotation.value().equals(testContextInstance.get().getAppServerContainerName())) .findFirst() - .orElseThrow(() -> new IllegalStateException("Not found the @AppServerContainer annotation with current app server.")); + .orElse(null); } private AppServerContainer getCorrespondingAnnotation(Class testClass) { @@ -107,7 +111,7 @@ public class AdapterTestExecutionDecider implements TestExecutionDecider { return appServerContainers.stream() .filter(annotation -> annotation.value().equals(testContextInstance.get().getAppServerContainerName())) .findFirst() - .orElseThrow(() -> new IllegalStateException("Not found the @AppServerContainer annotation with current app server.")); + .orElse(null); } private ExecutionDecision execute(Method method, Boolean execute, String message) { @@ -116,7 +120,7 @@ public class AdapterTestExecutionDecider implements TestExecutionDecider { return ExecutionDecision.execute(); } else { cache.put(method, new CachedRecord(Boolean.FALSE, message)); - log.debug(message); + log.debug(method.getName() + " " + message); return ExecutionDecision.dontExecute(message); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLFilterServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLFilterServletAdapterTest.java index b53be7ab02..8c0af722ee 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLFilterServletAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLFilterServletAdapterTest.java @@ -11,6 +11,7 @@ import org.keycloak.testsuite.arquillian.containers.ContainerConstants; /** * @author mhajas */ +@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW) @AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY) @AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY_DEPRECATED) @AppServerContainer(ContainerConstants.APP_SERVER_EAP) @@ -94,4 +95,18 @@ public class SAMLFilterServletAdapterTest extends SAMLServletAdapterTest { public void testErrorHandlingSigned() { } + + @Test + @Override + @Ignore + public void multiTenant1SamlTest() throws Exception { + + } + + @Test + @Override + @Ignore + public void multiTenant2SamlTest() throws Exception { + + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLServletAdapterTest.java index 47a2b9b500..431efb4045 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLServletAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLServletAdapterTest.java @@ -166,6 +166,7 @@ import org.xml.sax.SAXException; /** * @author mhajas */ +@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW) @AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY) @AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY_DEPRECATED) @AppServerContainer(ContainerConstants.APP_SERVER_EAP) @@ -265,10 +266,10 @@ public class SAMLServletAdapterTest extends AbstractServletsAdapterTest { protected EcpSP ecpSPPage; @Page - protected MultiTenant1Saml mutiTenant1SamlPage; + protected MultiTenant1Saml multiTenant1SamlPage; @Page - protected MultiTenant2Saml mutiTenant2SamlPage; + protected MultiTenant2Saml multiTenant2SamlPage; @Page protected SAMLPostLoginTenant1 tenant1RealmSAMLPostLoginPage; @@ -595,38 +596,50 @@ public class SAMLServletAdapterTest extends AbstractServletsAdapterTest { @Test public void multiTenant1SamlTest() throws Exception { - UserRepresentation user1 = createUserRepresentation("user-tenant1", "user-tenant1@redhat.com", "Bill", "Burke", true); - setPasswordFor(user1, "user-tenant1"); - // check the user in the tenant logs in ok - assertSuccessfulLogin(mutiTenant1SamlPage, user1, tenant1RealmSAMLPostLoginPage, "principal=user-tenant1"); - // check the issuer is the correct tenant - driver.navigate().to(mutiTenant1SamlPage.getUriBuilder().path("getAssertionIssuer").build().toASCIIString()); - waitUntilElement(By.xpath("//body")).text().contains("/auth/realms/tenant1"); - // check logout - mutiTenant1SamlPage.logout(); - checkLoggedOut(mutiTenant1SamlPage, tenant1RealmSAMLPostLoginPage); - // check a user in the other tenant doesn't login - UserRepresentation user2 = createUserRepresentation("user-tenant2", "user-tenant2@redhat.com", "Bill", "Burke", true); - setPasswordFor(user2, "user-tenant2"); - assertFailedLogin(mutiTenant1SamlPage, user2, tenant1RealmSAMLPostLoginPage); + multiTenant1SamlPage.setRolesToCheck("user"); + + try { + UserRepresentation user1 = createUserRepresentation("user-tenant1", "user-tenant1@redhat.com", "Bill", "Burke", true); + setPasswordFor(user1, "user-tenant1"); + // check the user in the tenant logs in ok + assertSuccessfulLogin(multiTenant1SamlPage, user1, tenant1RealmSAMLPostLoginPage, "principal=user-tenant1"); + // check the issuer is the correct tenant + driver.navigate().to(multiTenant1SamlPage.getUriBuilder().clone().path("getAssertionIssuer").build().toASCIIString()); + waitUntilElement(By.xpath("//body")).text().contains("/auth/realms/tenant1"); + // check logout + multiTenant1SamlPage.logout(); + checkLoggedOut(multiTenant1SamlPage, tenant1RealmSAMLPostLoginPage); + // check a user in the other tenant doesn't login + UserRepresentation user2 = createUserRepresentation("user-tenant2", "user-tenant2@redhat.com", "Bill", "Burke", true); + setPasswordFor(user2, "user-tenant2"); + assertFailedLogin(multiTenant1SamlPage, user2, tenant1RealmSAMLPostLoginPage); + } finally { + multiTenant1SamlPage.checkRolesEndPoint(false); + } } - + @Test public void multiTenant2SamlTest() throws Exception { - UserRepresentation user2 = createUserRepresentation("user-tenant2", "user-tenant2@redhat.com", "Bill", "Burke", true); - setPasswordFor(user2, "user-tenant2"); - // check the user in the tenant logs in ok - assertSuccessfulLogin(mutiTenant2SamlPage, user2, tenant2RealmSAMLPostLoginPage, "principal=user-tenant2"); - // check the issuer is the correct tenant - driver.navigate().to(mutiTenant2SamlPage.getUriBuilder().path("getAssertionIssuer").build().toASCIIString()); - waitUntilElement(By.xpath("//body")).text().contains("/auth/realms/tenant2"); - // check logout - mutiTenant2SamlPage.logout(); - checkLoggedOut(mutiTenant2SamlPage, tenant2RealmSAMLPostLoginPage); - // check a user in the other tenant doesn't login - UserRepresentation user1 = createUserRepresentation("user-tenant1", "user-tenant1@redhat.com", "Bill", "Burke", true); - setPasswordFor(user1, "user-tenant1"); - assertFailedLogin(mutiTenant2SamlPage, user1, tenant2RealmSAMLPostLoginPage); + multiTenant2SamlPage.setRolesToCheck("user"); + + try { + UserRepresentation user2 = createUserRepresentation("user-tenant2", "user-tenant2@redhat.com", "Bill", "Burke", true); + setPasswordFor(user2, "user-tenant2"); + // check the user in the tenant logs in ok + assertSuccessfulLogin(multiTenant2SamlPage, user2, tenant2RealmSAMLPostLoginPage, "principal=user-tenant2"); + // check the issuer is the correct tenant + driver.navigate().to(multiTenant2SamlPage.getUriBuilder().clone().path("getAssertionIssuer").build().toASCIIString()); + waitUntilElement(By.xpath("//body")).text().contains("/auth/realms/tenant2"); + // check logout + multiTenant2SamlPage.logout(); + checkLoggedOut(multiTenant2SamlPage, tenant2RealmSAMLPostLoginPage); + // check a user in the other tenant doesn't login + UserRepresentation user1 = createUserRepresentation("user-tenant1", "user-tenant1@redhat.com", "Bill", "Burke", true); + setPasswordFor(user1, "user-tenant1"); + assertFailedLogin(multiTenant2SamlPage, user1, tenant2RealmSAMLPostLoginPage); + } finally { + multiTenant2SamlPage.checkRolesEndPoint(false); + } } private static final KeyPair NEW_KEY_PAIR = KeyUtils.generateRsaKeyPair(1024); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/NonIDERunListener.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/NonIDERunListener.java index 17947e4b6c..d6aff45695 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/NonIDERunListener.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/NonIDERunListener.java @@ -40,12 +40,27 @@ public class NonIDERunListener extends RunListener { } private void disableKeycloakLogging() { - String loggingLevel = System.getProperty(KEYCLOAK_LOGGING_LEVEL_NAME); - if (loggingLevel == null || loggingLevel.isEmpty()) { + String loggingLevel = System.getProperty(KEYCLOAK_LOGGING_LEVEL_NAME, "").toLowerCase(); + if (loggingLevel.isEmpty()) { log.infof("Setting %s to off. Keycloak server logging will be disabled", KEYCLOAK_LOGGING_LEVEL_NAME); System.setProperty(KEYCLOAK_LOGGING_LEVEL_NAME, "off"); org.apache.log4j.Logger.getLogger("org.keycloak").setLevel(Level.OFF); + } else { + switch (loggingLevel) { + case "debug": + org.apache.log4j.Logger.getLogger("org.keycloak").setLevel(Level.DEBUG); + break; + case "trace": + org.apache.log4j.Logger.getLogger("org.keycloak").setLevel(Level.TRACE); + break; + case "all": + org.apache.log4j.Logger.getLogger("org.keycloak").setLevel(Level.ALL); + break; + default: + org.apache.log4j.Logger.getLogger("org.keycloak").setLevel(Level.INFO); + break; + } } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/multi-tenant-saml/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/multi-tenant-saml/WEB-INF/web.xml index 1720657cb3..a4f67a8756 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/multi-tenant-saml/WEB-INF/web.xml +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/multi-tenant-saml/WEB-INF/web.xml @@ -45,6 +45,18 @@ user + + + Unsecured-setCheckRoles + /setCheckRoles/* + + + + + Unsecured-uncheckRoles + /uncheckRoles/* + + KEYCLOAK-SAML diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml index ab98a521b6..825985f1ea 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml @@ -45,6 +45,18 @@ manager + + + Unsecured-setCheckRoles + /setCheckRoles/* + + + + + Unsecured-uncheckRoles + /uncheckRoles/* + + KEYCLOAK-SAML diff --git a/testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/undertow/SimpleWebXmlParser.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/undertow/SimpleWebXmlParser.java index eeef21905c..a77b6efcc4 100644 --- a/testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/undertow/SimpleWebXmlParser.java +++ b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/undertow/SimpleWebXmlParser.java @@ -55,33 +55,35 @@ class SimpleWebXmlParser { try { DocumentWrapper document = new DocumentWrapper(webXml); - // SERVLETS + if (di.getServlets().get("ResteasyServlet") == null) { - Map servletMappings = new HashMap<>(); - List sm = document.getElementsByTagName("servlet-mapping"); - for (ElementWrapper mapping : sm) { - String servletName = mapping.getElementByTagName("servlet-name").getText(); - String path = mapping.getElementByTagName("url-pattern").getText(); - servletMappings.put(servletName, path); - } + // SERVLETS + Map servletMappings = new HashMap<>(); + List sm = document.getElementsByTagName("servlet-mapping"); + for (ElementWrapper mapping : sm) { + String servletName = mapping.getElementByTagName("servlet-name").getText(); + String path = mapping.getElementByTagName("url-pattern").getText(); + servletMappings.put(servletName, path); + } - List servlets = document.getElementsByTagName("servlet"); - for (ElementWrapper servlet : servlets) { - String servletName = servlet.getElementByTagName("servlet-name").getText(); - ElementWrapper servletClassEw = servlet.getElementByTagName("servlet-class"); - String servletClass = servletClassEw == null ? servletName : servletClassEw.getText(); - ElementWrapper loadOnStartupEw = servlet.getElementByTagName("load-on-startup"); - Integer loadOnStartup = loadOnStartupEw == null ? null : Integer.valueOf(loadOnStartupEw.getText()); + List servlets = document.getElementsByTagName("servlet"); + for (ElementWrapper servlet : servlets) { + String servletName = servlet.getElementByTagName("servlet-name").getText(); + ElementWrapper servletClassEw = servlet.getElementByTagName("servlet-class"); + String servletClass = servletClassEw == null ? servletName : servletClassEw.getText(); + ElementWrapper loadOnStartupEw = servlet.getElementByTagName("load-on-startup"); + Integer loadOnStartup = loadOnStartupEw == null ? null : Integer.valueOf(loadOnStartupEw.getText()); - Class servletClazz = (Class) Class.forName(servletClass); - ServletInfo undertowServlet = new ServletInfo(servletName, servletClazz); + Class servletClazz = (Class) Class.forName(servletClass); + ServletInfo undertowServlet = new ServletInfo(servletName, servletClazz); - if (servletMappings.containsKey(servletName)) { - undertowServlet.addMapping(servletMappings.get(servletName)); - undertowServlet.setLoadOnStartup(loadOnStartup); - di.addServlet(undertowServlet); - } else { - log.warnf("Missing servlet-mapping for '%s'", servletName); + if (servletMappings.containsKey(servletName)) { + undertowServlet.addMapping(servletMappings.get(servletName)); + undertowServlet.setLoadOnStartup(loadOnStartup); + di.addServlet(undertowServlet); + } else { + log.warnf("Missing servlet-mapping for '%s'", servletName); + } } } @@ -180,21 +182,29 @@ class SimpleWebXmlParser { ElementWrapper sessionCfg = document.getElementByTagName("session-config"); if (sessionCfg != null) { ElementWrapper cookieConfig = sessionCfg.getElementByTagName("cookie-config"); - String httpOnly = cookieConfig.getElementByTagName("http-only").getText(); String cookieName = cookieConfig.getElementByTagName("name").getText(); ServletSessionConfig cfg = new ServletSessionConfig(); - cfg.setHttpOnly(Boolean.parseBoolean(httpOnly)); + if (cookieConfig.getElementByTagName("http-only") != null) { + cfg.setHttpOnly(Boolean.parseBoolean(cookieConfig.getElementByTagName("http-only").getText())); + } cfg.setName(cookieName); di.setServletSessionConfig(cfg); } // ERROR PAGES List errorPages = document.getElementsByTagName("error-page"); - for (ElementWrapper errorPage : errorPages) { - int errorCode = Integer.parseInt(errorPage.getElementByTagName("error-code").getText()); - String location = errorPage.getElementByTagName("location").getText(); - di.addErrorPage(new ErrorPage(location, errorCode)); + for (ElementWrapper errorPageWrapper : errorPages) { + String location = errorPageWrapper.getElementByTagName("location").getText(); + + ErrorPage errorPage; + if (errorPageWrapper.getElementByTagName("error-code") != null) { + errorPage = new ErrorPage(location, Integer.parseInt(errorPageWrapper.getElementByTagName("error-code").getText())); + } else { + errorPage = new ErrorPage(location); + } + + di.addErrorPage(errorPage); } } catch (ClassNotFoundException cnfe) { diff --git a/testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/undertow/UndertowDeployerHelper.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/undertow/UndertowDeployerHelper.java index bcd25b730d..cb91e398de 100644 --- a/testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/undertow/UndertowDeployerHelper.java +++ b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/undertow/UndertowDeployerHelper.java @@ -25,8 +25,6 @@ import io.undertow.server.handlers.resource.ResourceManager; import io.undertow.server.handlers.resource.URLResource; import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.ServletInfo; -import org.apache.jasper.deploy.JspPropertyGroup; -import org.apache.jasper.deploy.TagLibraryInfo; import org.arquillian.undertow.UndertowContainerConfiguration; import org.jboss.logging.Logger; import org.jboss.shrinkwrap.api.Archive; @@ -58,6 +56,10 @@ public class UndertowDeployerHelper { private static final Logger log = Logger.getLogger(UndertowDeployerHelper.class); public DeploymentInfo getDeploymentInfo(UndertowContainerConfiguration config, WebArchive archive) { + return getDeploymentInfo(config, archive, null); + } + + public DeploymentInfo getDeploymentInfo(UndertowContainerConfiguration config, WebArchive archive, DeploymentInfo di) { String archiveName = archive.getName(); String appName = archive.getName().substring(0, archive.getName().lastIndexOf('.')); @@ -69,7 +71,9 @@ public class UndertowDeployerHelper { String appContextUrl = "http://" + config.getBindAddress() + ":" + config.getBindHttpPort() + contextPath; try { - DeploymentInfo di = new DeploymentInfo(); + if (di == null) { + di = new DeploymentInfo(); + } UndertowWarClassLoader classLoader = new UndertowWarClassLoader(UndertowDeployerHelper.class.getClassLoader(), archive); di.setClassLoader(classLoader); @@ -89,7 +93,7 @@ public class UndertowDeployerHelper { di.addWelcomePages("index.html", "index.jsp"); - JspServletBuilder.setupDeployment(di, new HashMap(), new HashMap(), new HackInstanceManager()); + JspServletBuilder.setupDeployment(di, new HashMap<>(), new HashMap<>(), new HackInstanceManager()); addAnnotatedServlets(di, archive);