diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeServletDistributable.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeServletDistributable.java new file mode 100644 index 0000000000..ed547c09ba --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeServletDistributable.java @@ -0,0 +1,49 @@ +/* + * 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.testsuite.adapter.page; + +import org.jboss.arquillian.container.test.api.OperateOnDeployment; +import org.jboss.arquillian.test.api.ArquillianResource; + +import java.net.URL; +import org.openqa.selenium.WebDriver; + +/** + * @author mhajas + */ +public class EmployeeServletDistributable extends SAMLServlet { + public static final String DEPLOYMENT_NAME = "employee-distributable"; + + @ArquillianResource + @OperateOnDeployment(DEPLOYMENT_NAME) + private URL url; + + public EmployeeServletDistributable(WebDriver driver) { + super(); + this.driver = driver; + } + + @Override + public URL getInjectedUrl() { + return url; + } + + public void setUrl(URL url) { + this.url = url; + } +} 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 cc4a419725..2f226b929b 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 @@ -28,7 +28,7 @@ public abstract class SAMLServlet extends AbstractPageWithInjectedUrl { public void logout() { driver.navigate().to(getUriBuilder().queryParam("GLO", "true").build().toASCIIString()); - getUriBuilder().replaceQueryParam("GLO", null); + getUriBuilder().replaceQueryParam("GLO"); pause(300); } @@ -36,7 +36,7 @@ public abstract class SAMLServlet extends AbstractPageWithInjectedUrl { if (check) { getUriBuilder().queryParam("checkRoles", true); } else { - getUriBuilder().replaceQueryParam("checkRoles", null); + getUriBuilder().replaceQueryParam("checkRoles"); } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java index bd6e5a051f..e3950d3306 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java @@ -51,7 +51,7 @@ public class DeploymentTargetModifier extends AnnotationDeploymentScenarioGenera if (appServerQualifier != null && !appServerQualifier.isEmpty()) { for (DeploymentDescription deployment : deployments) { - if (deployment.getTarget() == null || !deployment.getTarget().getName().equals(appServerQualifier)) { + if (deployment.getTarget() == null || !deployment.getTarget().getName().startsWith(appServerQualifier)) { log.debug("Setting target container for " + deployment.getName() + ": " + appServerQualifier); deployment.setTarget(new TargetDescription(appServerQualifier)); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java index cc018d2267..235d15f8e0 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java @@ -65,11 +65,11 @@ public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest { return deployment; } - protected static WebArchive samlServletDeployment(String name, Class... servletClasses) { + public static WebArchive samlServletDeployment(String name, Class... servletClasses) { return samlServletDeployment(name, "web.xml", servletClasses); } - protected static WebArchive samlServletDeployment(String name, String webXMLPath, Class... servletClasses) { + public static WebArchive samlServletDeployment(String name, String webXMLPath, Class... servletClasses) { String baseSAMLPath = "/adapter-test/keycloak-saml/"; String webInfPath = baseSAMLPath + name + "/WEB-INF/"; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/cluster/AbstractSAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/cluster/AbstractSAMLAdapterClusterTest.java new file mode 100644 index 0000000000..3868fb5cee --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/cluster/AbstractSAMLAdapterClusterTest.java @@ -0,0 +1,237 @@ +/* + * Copyright 2017 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.adapter.servlet.cluster; + +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.UsersResource; +import org.keycloak.representations.idm.*; +import org.keycloak.testsuite.Retry; +import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable; +import org.keycloak.testsuite.adapter.page.SAMLServlet; +import org.keycloak.testsuite.auth.page.AuthRealm; +import org.keycloak.testsuite.auth.page.login.*; +import org.keycloak.testsuite.page.AbstractPage; +import org.keycloak.testsuite.util.WaitUtils; + +import io.undertow.Undertow; +import io.undertow.server.handlers.ResponseCodeHandler; +import io.undertow.server.handlers.proxy.LoadBalancingProxyClient; +import io.undertow.server.handlers.proxy.ProxyHandler; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.function.Consumer; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.jboss.arquillian.container.test.api.*; +import org.jboss.arquillian.graphene.page.Page; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.junit.*; + +import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest; +import org.keycloak.testsuite.admin.ApiUtil; +import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; + +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.WebDriverWait; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.keycloak.testsuite.AbstractAuthTest.createUserRepresentation; +import static org.keycloak.testsuite.admin.Users.setPasswordFor; +import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getNearestSuperclassWithAnnotation; +import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO; +import static org.keycloak.testsuite.util.IOUtil.loadRealm; +import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; + +/** + * + * @author hmlnarik + */ +public abstract class AbstractSAMLAdapterClusterTest extends AbstractServletsAdapterTest { + + protected static final String NODE_1_NAME = "ha-node-1"; + protected static final String NODE_2_NAME = "ha-node-2"; + + protected final String NODE_1_SERVER_NAME = getAppServerId() + "-" + NODE_1_NAME; + protected final String NODE_2_SERVER_NAME = getAppServerId() + "-" + NODE_2_NAME; + + protected static final int PORT_OFFSET_NODE_REVPROXY = NumberUtils.toInt(System.getProperty("app.server.reverse-proxy.port.offset"), -1); + protected static final int HTTP_PORT_NODE_REVPROXY = 8080 + PORT_OFFSET_NODE_REVPROXY; + protected static final int PORT_OFFSET_NODE_1 = NumberUtils.toInt(System.getProperty("app.server.1.port.offset"), -1); + protected static final int HTTP_PORT_NODE_1 = 8080 + PORT_OFFSET_NODE_1; + protected static final int PORT_OFFSET_NODE_2 = NumberUtils.toInt(System.getProperty("app.server.2.port.offset"), -1); + protected static final int HTTP_PORT_NODE_2 = 8080 + PORT_OFFSET_NODE_2; + protected static final URI NODE_1_URI = URI.create("http://localhost:" + HTTP_PORT_NODE_1); + protected static final URI NODE_2_URI = URI.create("http://localhost:" + HTTP_PORT_NODE_2); + + @BeforeClass + public static void checkPropertiesSet() { + Assume.assumeThat(PORT_OFFSET_NODE_1, not(is(-1))); + Assume.assumeThat(PORT_OFFSET_NODE_2, not(is(-1))); + Assume.assumeThat(PORT_OFFSET_NODE_REVPROXY, not(is(-1))); + } + + protected static void prepareServerDirectory(String targetSubdirectory) throws IOException { + Path path = Paths.get(System.getProperty("app.server.home"), targetSubdirectory); + File targetSubdirFile = path.toFile(); + FileUtils.deleteDirectory(targetSubdirFile); + FileUtils.forceMkdir(targetSubdirFile); + FileUtils.copyDirectoryToDirectory(Paths.get(System.getProperty("app.server.home"), "standalone", "deployments").toFile(), targetSubdirFile); + } + protected LoadBalancingProxyClient loadBalancerToNodes; + protected Undertow reverseProxyToNodes; + + @ArquillianResource + protected ContainerController controller; + + @ArquillianResource + protected Deployer deployer; + + @Page + LoginActions loginActionsPage; + + @Override + public void addTestRealms(List testRealms) { + testRealms.add(loadRealm("/adapter-test/keycloak-saml/testsaml-behind-lb.json")); + } + + @Before + public void prepareReverseProxy() throws Exception { + loadBalancerToNodes = new LoadBalancingProxyClient().addHost(NODE_1_URI, NODE_1_NAME).setConnectionsPerThread(10); + reverseProxyToNodes = Undertow.builder().addHttpListener(HTTP_PORT_NODE_REVPROXY, "localhost").setIoThreads(2).setHandler(new ProxyHandler(loadBalancerToNodes, 5000, ResponseCodeHandler.HANDLE_404)).build(); + reverseProxyToNodes.start(); + } + + @After + public void stopReverseProxy() { + reverseProxyToNodes.stop(); + } + + @Before + public void startServer() throws Exception { + prepareServerDirectory("standalone-" + NODE_1_NAME); + controller.start(NODE_1_SERVER_NAME); + prepareWorkerNode(Integer.valueOf(System.getProperty("app.server.1.management.port"))); + prepareServerDirectory("standalone-" + NODE_2_NAME); + controller.start(NODE_2_SERVER_NAME); + prepareWorkerNode(Integer.valueOf(System.getProperty("app.server.2.management.port"))); + deployer.deploy(EmployeeServletDistributable.DEPLOYMENT_NAME); + deployer.deploy(EmployeeServletDistributable.DEPLOYMENT_NAME + "_2"); + } + + protected abstract void prepareWorkerNode(Integer managementPort) throws Exception; + + @After + public void stopServer() { + controller.stop(NODE_1_SERVER_NAME); + controller.stop(NODE_2_SERVER_NAME); + } + + @Override + public void setDefaultPageUriParameters() { + super.setDefaultPageUriParameters(); + + testRealmSAMLPostLoginPage.setAuthRealm(DEMO); + loginPage.setAuthRealm(DEMO); + loginActionsPage.setAuthRealm(DEMO); + } + + protected void testLogoutViaSessionIndex(URL employeeUrl, Consumer logoutFunction) { + EmployeeServletDistributable page = PageFactory.initElements(driver, EmployeeServletDistributable.class); + page.setUrl(employeeUrl); + page.getUriBuilder().port(HTTP_PORT_NODE_REVPROXY); + + UserRepresentation bburkeUser = createUserRepresentation("bburke", "bburke@redhat.com", "Bill", "Burke", true); + setPasswordFor(bburkeUser, CredentialRepresentation.PASSWORD); + + assertSuccessfulLogin(page, bburkeUser, testRealmSAMLPostLoginPage, "principal=bburke"); + + updateProxy(NODE_2_NAME, NODE_2_URI, NODE_1_URI); + logoutFunction.accept(page); + delayedCheckLoggedOut(page, loginActionsPage); + + updateProxy(NODE_1_NAME, NODE_1_URI, NODE_2_URI); + delayedCheckLoggedOut(page, loginActionsPage); + } + + @Test + public void testBackchannelLogout(@ArquillianResource + @OperateOnDeployment(value = EmployeeServletDistributable.DEPLOYMENT_NAME) URL employeeUrl) throws Exception { + testLogoutViaSessionIndex(employeeUrl, (EmployeeServletDistributable page) -> { + RealmResource demoRealm = adminClient.realm(DEMO); + String bburkeId = ApiUtil.findUserByUsername(demoRealm, "bburke").getId(); + demoRealm.users().get(bburkeId).logout(); + log.infov("Logged out via admin console"); + }); + } + + @Test + public void testFrontchannelLogout(@ArquillianResource + @OperateOnDeployment(value = EmployeeServletDistributable.DEPLOYMENT_NAME) URL employeeUrl) throws Exception { + testLogoutViaSessionIndex(employeeUrl, (EmployeeServletDistributable page) -> { + page.logout(); + log.infov("Logged out via application"); + }); + } + + protected void updateProxy(String hostToPointToName, URI hostToPointToUri, URI hostToRemove) { + loadBalancerToNodes.removeHost(hostToRemove); + loadBalancerToNodes.addHost(hostToPointToUri, hostToPointToName); + log.infov("Reverse proxy will direct requests to {0}", hostToPointToUri); + } + + protected void assertSuccessfulLogin(SAMLServlet page, UserRepresentation user, Login loginPage, String expectedString) { + page.navigateTo(); + assertCurrentUrlStartsWith(loginPage); + loginPage.form().login(user); + WebDriverWait wait = new WebDriverWait(driver, WaitUtils.PAGELOAD_TIMEOUT_MILLIS / 1000); + wait.until((WebDriver d) -> d.getPageSource().contains(expectedString)); + } + + protected void delayedCheckLoggedOut(AbstractPage page, AuthRealm loginPage) { + Retry.execute(() -> { + try { + checkLoggedOut(page, loginPage); + } catch (AssertionError | TimeoutException ex) { + driver.navigate().refresh(); + log.debug("[Retriable] Timed out waiting for login page"); + throw new RuntimeException(ex); + } + }, 10, 100); + } + + protected void checkLoggedOut(AbstractPage page, AuthRealm loginPage) { + page.navigateTo(); + WaitUtils.waitForPageToLoad(driver); + assertCurrentUrlStartsWith(loginPage); + } + + private String getAppServerId() { + Class annotatedClass = getNearestSuperclassWithAnnotation(this.getClass(), AppServerContainer.class); + + return (annotatedClass == null ? "" + : annotatedClass.getAnnotation(AppServerContainer.class).value()); + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/keycloak-saml.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/keycloak-saml.xml new file mode 100644 index 0000000000..60f48de3ec --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/keycloak-saml.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml-behind-lb.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml-behind-lb.json new file mode 100644 index 0000000000..ae10da28d9 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml-behind-lb.json @@ -0,0 +1,164 @@ +{ + "id": "demo", + "realm": "demo", + "enabled": true, + "sslRequired": "external", + "registrationAllowed": true, + "resetPasswordAllowed": true, + "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", + "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", + "requiredCredentials": [ "password" ], + "defaultRoles": [ "user" ], + "smtpServer": { + "from": "auto@keycloak.org", + "host": "localhost", + "port":"3025" + }, + "users" : [ + { + "username" : "bburke", + "enabled": true, + "email" : "bburke@redhat.com", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "attributes" : { + "phone": "617" + }, + "realmRoles": ["manager", "user"], + "applicationRoles": { + "http://localhost:8580/employee-distributable/": [ "employee" ] + } + }, + { + "username" : "unauthorized", + "enabled": true, + "email" : "unauthorized@redhat.com", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ] + }, + { + "username" : "topGroupUser", + "enabled": true, + "email" : "top@redhat.com", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "groups": [ + "/top" + ] + }, + { + "username" : "level2GroupUser", + "enabled": true, + "email" : "level2@redhat.com", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "groups": [ + "/top/level2" + ] + } + ], + "clients": [ + { + "clientId": "http://localhost:8580/employee-distributable/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8580/employee-distributable", + "redirectUris": [ + "http://localhost:8580/employee-distributable/*" + ], + "attributes": { + "saml_assertion_consumer_url_post": "http://localhost:8580/employee-distributable/saml", + "saml_assertion_consumer_url_redirect": "http://localhost:8580/employee-distributable/saml", + "saml_single_logout_service_url_post": "http://localhost:8580/employee-distributable/saml", + "saml_single_logout_service_url_redirect": "http://localhost:8580/employee-distributable/saml", + "saml.authnstatement": "true" + }, + "protocolMappers": [ + { + "name": "email", + "protocol": "saml", + "protocolMapper": "saml-user-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "email", + "friendly.name": "email", + "attribute.name": "urn:oid:1.2.840.113549.1.9.1", + "attribute.nameformat": "URI Reference" + } + }, + { + "name": "phone", + "protocol": "saml", + "protocolMapper": "saml-user-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "phone", + "attribute.name": "phone", + "attribute.nameformat": "Basic" + } + }, + { + "name": "role-list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "attribute.name": "Role", + "attribute.nameformat": "Basic", + "single": "false" + } + } + ] + } + ], + "groups" : [ + { + "name": "top", + "attributes": { + "topAttribute": ["true"] + + }, + "realmRoles": ["manager"], + "subGroups": [ + { + "name": "level2", + "realmRoles": ["user"], + "attributes": { + "level2Attribute": ["true"] + + } + } + ] + } + ], + + "roles" : { + "realm" : [ + { + "name": "manager", + "description": "Have Manager privileges" + }, + { + "name": "user", + "description": "Have User privileges" + } + ], + "application" : { + "http://localhost:8580/employee-distributable/" : [ + { + "name": "employee", + "description": "Have Employee privileges" + } + ] + } + } +} diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl index 74541a0193..30e7dba1f0 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl @@ -48,6 +48,53 @@ + + + true + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${app.server.home} + ${app.server.java.home} + ${app.server.home}/standalone-ha-node-1 + standalone-ha.xml + + -Djboss.socket.binding.port-offset=${app.server.1.port.offset} + -Djboss.node.name=ha-node-1 + ${adapter.test.props} + + + -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7901 + ${app.server.memory.settings} + -Djava.net.preferIPv4Stack=true + + ${app.server.management.protocol} + ${app.server.1.management.port} + ${app.server.startup.timeout} + + + + + + true + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${app.server.home} + ${app.server.java.home} + ${app.server.home}/standalone-ha-node-2 + standalone-ha.xml + + -Djboss.socket.binding.port-offset=${app.server.2.port.offset} + -Djboss.node.name=ha-node-2 + ${adapter.test.props} + + + -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7902 + ${app.server.memory.settings} + -Djava.net.preferIPv4Stack=true + + ${app.server.management.protocol} + ${app.server.2.management.port} + ${app.server.startup.timeout} + + diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/pom.xml index 7c56a488c2..35f9501783 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/pom.xml @@ -30,12 +30,29 @@ integration-arquillian-tests-adapters-eap6 Adapter Tests - JBoss - EAP 6 - + + + + org.wildfly.extras.creaper + creaper-core + test + 1.5.0 + + + org.wildfly.core + wildfly-cli + test + 2.2.0.Final + + + eap6 remote ${app.server.management.port.jmx} + ${app.server.1.management.port.jmx} + ${app.server.2.management.port.jmx} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java new file mode 100644 index 0000000000..f0a166bea4 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2017 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.adapter.cluster; + +import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable; +import org.keycloak.testsuite.arquillian.annotation.*; + +import java.io.*; + +import org.keycloak.testsuite.adapter.servlet.cluster.AbstractSAMLAdapterClusterTest; +import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.TargetsContainer; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Assert; +import org.wildfly.extras.creaper.core.*; +import org.wildfly.extras.creaper.core.online.*; +import org.wildfly.extras.creaper.core.online.operations.*; + +import static org.keycloak.testsuite.adapter.AbstractServletsAdapterTest.samlServletDeployment; + +/** + * + * @author hmlnarik + */ +@AppServerContainer("app-server-eap6") +public class EAP6SAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest { + + @TargetsContainer(value = "app-server-eap6-" + NODE_1_NAME) + @Deployment(name = EmployeeServletDistributable.DEPLOYMENT_NAME, managed = false) + protected static WebArchive employee() { + return samlServletDeployment(EmployeeServletDistributable.DEPLOYMENT_NAME, EmployeeServletDistributable.DEPLOYMENT_NAME + "/WEB-INF/web.xml", SendUsernameServlet.class); + } + + @TargetsContainer(value = "app-server-eap6-" + NODE_2_NAME) + @Deployment(name = EmployeeServletDistributable.DEPLOYMENT_NAME + "_2", managed = false) + protected static WebArchive employee2() { + return employee(); + } + + @Override + protected void prepareWorkerNode(Integer managementPort) throws IOException, CliException, NumberFormatException { + log.infov("Preparing worker node ({0})", managementPort); + + OnlineManagementClient clientWorkerNodeClient = ManagementClient.online(OnlineOptions + .standalone() + .hostAndPort("localhost", managementPort) + .protocol(ManagementProtocol.REMOTE) + .build()); + Operations op = new Operations(clientWorkerNodeClient); + + Batch b = new Batch(); + Address tcppingStack = Address + .subsystem("jgroups") + .and("stack", "tcpping"); + b.add(tcppingStack); + b.add(tcppingStack.and("transport", "TRANSPORT"), Values.of("socket-binding", "jgroups-tcp").and("type", "TCP")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "TCPPING")); + b.add(tcppingStack.and("protocol", "TCPPING").and("property", "initial_hosts"), Values.of("value", "localhost[" + (7600 + PORT_OFFSET_NODE_1) + "],localhost[" + (7600 + PORT_OFFSET_NODE_2) + "]")); + b.add(tcppingStack.and("protocol", "TCPPING").and("property", "port_range"), Values.of("value", "0")); + b.add(tcppingStack.and("protocol", "TCPPING").and("property", "num_initial_members"), Values.of("value", "2")); + b.add(tcppingStack.and("protocol", "TCPPING").and("property", "timeout"), Values.of("value", "3000")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "MERGE2")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "FD_SOCK").and("socket-binding", "jgroups-tcp-fd")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "FD")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "VERIFY_SUSPECT")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "pbcast.NAKACK")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "UNICAST2")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "pbcast.STABLE")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "pbcast.GMS")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "UFC")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "MFC")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "FRAG2")); + b.invoke("add-protocol", tcppingStack, Values.of("type", "RSVP")); + Assert.assertTrue("Could not add TCPPING JGroups stack", op.batch(b).isSuccess()); + + Assert.assertTrue(op.writeAttribute(Address.subsystem("jgroups"), "default-stack", "tcpping").isSuccess()); + Assert.assertTrue(op.writeAttribute(Address.subsystem("web"), "instance-id", "${jboss.node.name}").isSuccess()); + Assert.assertTrue(op.add(Address.extension("org.keycloak.keycloak-saml-adapter-subsystem"), Values.of("module", "org.keycloak.keycloak-saml-adapter-subsystem")).isSuccess()); + Assert.assertTrue(op.add(Address.subsystem("keycloak-saml")).isSuccess()); + + clientWorkerNodeClient.execute("reload"); + + log.infov("Worker node ({0}) Prepared", managementPort); + } + +} diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/web.xml new file mode 100644 index 0000000000..767eb6c161 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/web.xml @@ -0,0 +1,62 @@ + + + + + + + + + + %CONTEXT_PATH% + + + javax.ws.rs.core.Application + /* + + + + /error.html + + + + + Application + /* + + + manager + + + + + KEYCLOAK-SAML + demo + + + + manager + + + + keycloak.sessionIdMapperUpdater.classes + org.keycloak.adapters.saml.jbossweb.infinispan.InfinispanSessionCacheIdMapperUpdater + + diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml index 885a052904..912947ff44 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml @@ -30,7 +30,22 @@ integration-arquillian-tests-adapters-wildfly Adapter Tests - JBoss - Wildfly - + + + + org.wildfly.extras.creaper + creaper-core + test + 1.5.0 + + + org.wildfly.core + wildfly-cli + test + 2.2.0.Final + + + wildfly diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java new file mode 100644 index 0000000000..eb7973c37d --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 2017 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.adapter.cluster; + +import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable; +import org.keycloak.testsuite.arquillian.annotation.*; + +import java.io.*; + +import org.keycloak.testsuite.adapter.servlet.cluster.AbstractSAMLAdapterClusterTest; +import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.TargetsContainer; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.wildfly.extras.creaper.core.*; +import org.wildfly.extras.creaper.core.online.*; +import org.wildfly.extras.creaper.core.online.operations.*; + +import static org.keycloak.testsuite.adapter.AbstractServletsAdapterTest.samlServletDeployment; + +/** + * + * @author hmlnarik + */ +@AppServerContainer("app-server-wildfly") +public class WildflySAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest { + + @TargetsContainer(value = "app-server-wildfly-" + NODE_1_NAME) + @Deployment(name = EmployeeServletDistributable.DEPLOYMENT_NAME, managed = false) + protected static WebArchive employee() { + return samlServletDeployment(EmployeeServletDistributable.DEPLOYMENT_NAME, EmployeeServletDistributable.DEPLOYMENT_NAME + "/WEB-INF/web.xml", SendUsernameServlet.class); + } + + @TargetsContainer(value = "app-server-wildfly-" + NODE_2_NAME) + @Deployment(name = EmployeeServletDistributable.DEPLOYMENT_NAME + "_2", managed = false) + protected static WebArchive employee2() { + return employee(); + } + + @Override + protected void prepareWorkerNode(Integer managementPort) throws IOException, CliException, NumberFormatException { + log.infov("Preparing worker node ({0})", managementPort); + + OnlineManagementClient clientWorkerNodeClient = ManagementClient.online(OnlineOptions + .standalone() + .hostAndPort("localhost", managementPort) + .build()); + Operations op = new Operations(clientWorkerNodeClient); + + Batch b = new Batch(); + Address tcppingStack = Address + .subsystem("jgroups") + .and("stack", "tcpping"); + b.add(tcppingStack); + b.add(tcppingStack.and("transport", "TCP"), Values.of("socket-binding", "jgroups-tcp")); + b.add(tcppingStack.and("protocol", "TCPPING")); + b.add(tcppingStack.and("protocol", "TCPPING").and("property", "initial_hosts"), Values.of("value", "localhost[" + (7600 + PORT_OFFSET_NODE_1) + "],localhost[" + (7600 + PORT_OFFSET_NODE_2) + "]")); + b.add(tcppingStack.and("protocol", "TCPPING").and("property", "port_range"), Values.of("value", "0")); + b.add(tcppingStack.and("protocol", "TCPPING").and("property", "num_initial_members"), Values.of("value", "2")); + b.add(tcppingStack.and("protocol", "TCPPING").and("property", "timeout"), Values.of("value", "3000")); + b.add(tcppingStack.and("protocol", "MERGE3")); + b.add(tcppingStack.and("protocol", "FD_SOCK"), Values.of("socket-binding", "jgroups-tcp-fd")); + b.add(tcppingStack.and("protocol", "FD")); + b.add(tcppingStack.and("protocol", "VERIFY_SUSPECT")); + b.add(tcppingStack.and("protocol", "pbcast.NAKACK2")); + b.add(tcppingStack.and("protocol", "UNICAST3")); + b.add(tcppingStack.and("protocol", "pbcast.STABLE")); + b.add(tcppingStack.and("protocol", "pbcast.GMS")); + b.add(tcppingStack.and("protocol", "MFC")); + b.add(tcppingStack.and("protocol", "FRAG2")); + b.writeAttribute(Address.subsystem("jgroups").and("channel", "ee"), "stack", "tcpping"); + op.batch(b); + + op.add(Address.extension("org.keycloak.keycloak-saml-adapter-subsystem"), Values.of("module", "org.keycloak.keycloak-saml-adapter-subsystem")); + op.add(Address.subsystem("keycloak-saml")); + + clientWorkerNodeClient.execute("reload"); + + log.infov("Worker node ({0}) Prepared", managementPort); + } + +} diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/web.xml new file mode 100644 index 0000000000..b57928f585 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/resources/adapter-test/keycloak-saml/employee-distributable/WEB-INF/web.xml @@ -0,0 +1,62 @@ + + + + + + + + + + %CONTEXT_PATH% + + + javax.ws.rs.core.Application + /* + + + + /error.html + + + + + Application + /* + + + manager + + + + + KEYCLOAK-SAML + demo + + + + manager + + + + keycloak.sessionIdMapperUpdater.classes + org.keycloak.adapters.saml.wildfly.infinispan.InfinispanSessionCacheIdMapperUpdater + + diff --git a/testsuite/integration-arquillian/tests/other/adapters/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/pom.xml index 6b6399738e..624839c9da 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/pom.xml @@ -54,6 +54,14 @@ false + 500 + 300 + 10290 + 10299 + 400 + 10390 + 10399 + @@ -193,6 +201,14 @@ ${app.server.startup.timeout} ${app.server.memory.settings} + ${app.server.reverse-proxy.port.offset} + + ${app.server.1.port.offset} + ${app.server.1.management.port} + + ${app.server.2.port.offset} + ${app.server.2.management.port} + ${adapter.test.props} ${adapter.config.bundled}