keycloak-aplcache

Details

diff --git a/testsuite/integration-arquillian/HOW-TO-RUN.md b/testsuite/integration-arquillian/HOW-TO-RUN.md
index 928038c..cd2eb26 100644
--- a/testsuite/integration-arquillian/HOW-TO-RUN.md
+++ b/testsuite/integration-arquillian/HOW-TO-RUN.md
@@ -635,8 +635,9 @@ For **JBoss-based** Keycloak backend containers on real DB, the previous command
 First we will manually download, configure and run infinispan servers. Then we can run the tests from IDE against the servers. 
 It's more effective during development as there is no need to restart infinispan server(s) among test runs.
 
-1) Download infinispan server 8.2.X from http://infinispan.org/download/ and go through the steps 
-from the [Keycloak Cross-DC documentation](http://www.keycloak.org/docs/latest/server_installation/index.html#jdgsetup) for setup infinispan servers.
+1) Download infinispan server of corresponding version (See "infinispan.version" property in [root pom.xml](../../pom.xml)) 
+from http://infinispan.org/download/ and go through the steps from the 
+[Keycloak Cross-DC documentation](http://www.keycloak.org/docs/latest/server_installation/index.html#jdgsetup) for setup infinispan servers.
 
 The difference to original docs is, that you need to have JDG servers available on localhost with port offsets. So:
 
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/ant/configure.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/common/ant/configure.xml
index 050e2fa..bfd0211 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/ant/configure.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/ant/configure.xml
@@ -2,7 +2,9 @@
 
     <target name="check-configuration-state">
         <available property="crossdc-configured" file="${project.build.directory}/crossdc-configured"/>
+        <available property="cluster-configured" file="${project.build.directory}/cluster-configured"/>
         <echo>crossdc-configured: ${crossdc-configured}</echo>
+        <echo>cluster-configured: ${cluster-configured}</echo>
     </target>
     
     <macrodef name="bin-chmod">
@@ -33,4 +35,14 @@
         <touch file="${project.build.directory}/crossdc-configured"/>
     </target>
 
+    <!-- TODO: will be better if other subsystems are configured through CLI as well rather than XSL -->
+    <target name="undertow-subsystem-cluster" unless="cluster-configured" depends="check-configuration-state">
+        <bin-chmod/>
+        <exec dir="${auth.server.home}/bin" executable="./${jboss.cli.executable}" failonerror="true">
+            <arg value="--file=${common.resources}/jboss-cli/undertow-subsystem-cluster-setup.cli"/>
+        </exec>
+        <cleanup/>
+        <touch file="${project.build.directory}/cluster-configured"/>
+    </target>
+
 </project>
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/jboss-cli/undertow-subsystem-cluster-setup.cli b/testsuite/integration-arquillian/servers/auth-server/jboss/common/jboss-cli/undertow-subsystem-cluster-setup.cli
new file mode 100644
index 0000000..3b923e3
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/jboss-cli/undertow-subsystem-cluster-setup.cli
@@ -0,0 +1,8 @@
+embed-server --server-config=standalone-ha.xml
+
+echo **** Begin ****
+
+echo *** Update undertow subsystem ***
+/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)
+
+echo **** End ****
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
index 7f02857..10e4760 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
@@ -775,7 +775,24 @@
                                 </execution>
                             </executions>
                         </plugin>
-                        
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-antrun-plugin</artifactId>
+                            <executions>
+                                <execution>
+                                    <id>configure-undertow-subsystem</id>
+                                    <phase>process-resources</phase>
+                                    <goals>
+                                        <goal>run</goal>
+                                    </goals>
+                                    <configuration>
+                                        <target>
+                                            <ant antfile="${common.resources}/ant/configure.xml" target="undertow-subsystem-cluster" />
+                                        </target>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
                     </plugins>
                 </pluginManagement>
             </build>
diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
index a5dbfa3..ff0127b 100644
--- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
+++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
@@ -18,7 +18,9 @@
 package org.keycloak.testsuite.arquillian.undertow;
 
 import io.undertow.Undertow;
+import io.undertow.server.HttpHandler;
 import io.undertow.server.handlers.PathHandler;
+import io.undertow.server.handlers.ProxyPeerAddressHandler;
 import io.undertow.servlet.Servlets;
 import io.undertow.servlet.api.DefaultServletConfig;
 import io.undertow.servlet.api.DeploymentInfo;
@@ -72,7 +74,7 @@ public class KeycloakOnUndertow implements DeployableContainer<KeycloakOnUnderto
 
     protected final Logger log = Logger.getLogger(this.getClass());
     
-    private UndertowJaxrsServer undertow;
+    private KeycloakUndertowJaxrsServer undertow;
     private KeycloakOnUndertowConfiguration configuration;
     private KeycloakSessionFactory sessionFactory;
 
@@ -187,7 +189,7 @@ public class KeycloakOnUndertow implements DeployableContainer<KeycloakOnUnderto
         long start = System.currentTimeMillis();
 
         if (undertow == null) {
-            undertow = new UndertowJaxrsServer();
+            undertow = new KeycloakUndertowJaxrsServer();
         }
 
         undertow.start(Undertow.builder()
@@ -281,4 +283,29 @@ public class KeycloakOnUndertow implements DeployableContainer<KeycloakOnUnderto
         throw new UnsupportedOperationException("Not implemented");
     }
 
+
+    private static class KeycloakUndertowJaxrsServer extends UndertowJaxrsServer {
+
+        @Override
+        public KeycloakUndertowJaxrsServer start(Undertow.Builder builder) {
+            try {
+                // Need to wrap the original handler with ProxyPeerAddressHandler. Thanks to that, if undertow is behind proxy and the proxy
+                // forwards "https" request to undertow as "http" request, undertow will be able to establish protocol correctly on the request
+                // based on the X-Proto headers
+                Field f = UndertowJaxrsServer.class.getDeclaredField("root");
+                f.setAccessible(true);
+                HttpHandler origRootHandler = (HttpHandler) f.get(this);
+
+                HttpHandler wrappedHandler = new ProxyPeerAddressHandler(origRootHandler);
+
+                server = builder.setHandler(wrappedHandler).build();
+                server.start();
+                return this;
+            } catch (NoSuchFieldException | IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+    }
+
 }
diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertowConfiguration.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertowConfiguration.java
index a526d96..b7a250a 100644
--- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertowConfiguration.java
+++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertowConfiguration.java
@@ -118,7 +118,12 @@ public class KeycloakOnUndertowConfiguration extends UndertowContainerConfigurat
         int basePort = getBindHttpPort();
         int newPort = basePort + bindHttpPortOffset;
         setBindHttpPort(newPort);
-        log.info("KeycloakOnUndertow will listen on port: " + newPort);
+
+        int baseHttpsPort = getBindHttpsPort();
+        int newHttpsPort = baseHttpsPort + bindHttpsPortOffset;
+        setBindHttpsPort(newHttpsPort);
+
+        log.info("KeycloakOnUndertow will listen for http on port: " + newPort + " and for https on port: " + newHttpsPort);
         
         if (this.keycloakConfigPropertyOverrides != null) {
             try {
diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/lb/SimpleUndertowLoadBalancer.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/lb/SimpleUndertowLoadBalancer.java
index 40f4bb2..bf65141 100644
--- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/lb/SimpleUndertowLoadBalancer.java
+++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/lb/SimpleUndertowLoadBalancer.java
@@ -104,7 +104,7 @@ public class SimpleUndertowLoadBalancer {
                     .build();
             undertow.start();
 
-            log.infof("#### Loadbalancer started and ready to serve requests on http://%s:%d, http://%s:%d ####", host, httpPort, host, httpsPort);
+            log.infof("#### Loadbalancer started and ready to serve requests on http://%s:%d, https://%s:%d ####", host, httpPort, host, httpsPort);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java
index 236d7bb..95d2a11 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java
@@ -112,6 +112,10 @@ public class AuthServerTestEnricher {
     public static final String AUTH_SERVER_CROSS_DC_PROPERTY = "auth.server.crossdc";
     public static final boolean AUTH_SERVER_CROSS_DC = Boolean.parseBoolean(System.getProperty(AUTH_SERVER_CROSS_DC_PROPERTY, "false"));
 
+    public static final String CACHE_SERVER_LIFECYCLE_SKIP_PROPERTY = "cache.server.lifecycle.skip";
+    public static final boolean CACHE_SERVER_LIFECYCLE_SKIP = Boolean.parseBoolean(System.getProperty(CACHE_SERVER_LIFECYCLE_SKIP_PROPERTY, "false"));
+
+
     public static final Boolean START_MIGRATION_CONTAINER = "auto".equals(System.getProperty("migration.mode")) ||
             "manual".equals(System.getProperty("migration.mode"));
 
@@ -226,8 +230,7 @@ public class AuthServerTestEnricher {
             if (suiteContext.getDcAuthServerBackendsInfo().stream().anyMatch(List::isEmpty)) {
                 throw new RuntimeException(String.format("Some data center has no auth server container matching '%s' defined in arquillian.xml.", AUTH_SERVER_BACKEND));
             }
-            boolean cacheServerLifecycleSkip = Boolean.parseBoolean(System.getProperty("cache.server.lifecycle.skip"));
-            if (suiteContext.getCacheServersInfo().isEmpty() && !cacheServerLifecycleSkip) {
+            if (suiteContext.getCacheServersInfo().isEmpty() && !CACHE_SERVER_LIFECYCLE_SKIP) {
                 throw new IllegalStateException("Cache containers misconfiguration");
             }
 
@@ -369,21 +372,39 @@ public class AuthServerTestEnricher {
     public void initializeTLS(@Observes(precedence = 3) BeforeClass event) throws Exception {
         // TLS for Undertow is configured in KeycloakOnUndertow since it requires
         // SSLContext while initializing HTTPS handlers
-        if (AUTH_SERVER_SSL_REQUIRED && isAuthServerJBossBased() && !suiteContext.isAuthServerCrossDc()) {
-            log.info("\n\n### Setting up TLS ##\n\n");
+        if (!suiteContext.isAuthServerCrossDc() && !suiteContext.isAuthServerCluster()) {
+            initializeTLS(suiteContext.getAuthServerInfo());
+        }
+    }
 
+    public static void initializeTLS(ContainerInfo containerInfo) {
+        if (AUTH_SERVER_SSL_REQUIRED && containerInfo.isJBossBased()) {
+            log.infof("\n\n### Setting up TLS for %s ##\n\n", containerInfo);
             try {
-                OnlineManagementClient client = getManagementClient();
-                enableTLS(client);
+                OnlineManagementClient client = getManagementClient(containerInfo);
+                AuthServerTestEnricher.enableTLS(client);
                 client.close();
             } catch (Exception e) {
-                log.warn("Failed to set up TLS. This may lead to unexpected behavior unless the test" +
-                      " sets it up manually", e);
+                log.warn("Failed to set up TLS for container '" + containerInfo.getQualifier() + "'. This may lead to unexpected behavior unless the test" +
+                        " sets it up manually", e);
             }
+
+        }
+    }
+
+    private static OnlineManagementClient getManagementClient(ContainerInfo containerInfo) {
+        try {
+            return ManagementClient.online(OnlineOptions
+                    .standalone()
+                    .hostAndPort("localhost", Integer.valueOf(containerInfo.getProperties().get("managementPort")))
+                    .build()
+            );
+        } catch (IOException e) {
+            throw new RuntimeException(e);
         }
     }
 
-    protected static void enableTLS(OnlineManagementClient client) throws Exception {
+    private static void enableTLS(OnlineManagementClient client) throws Exception {
         Administration administration = new Administration(client);
         Operations operations = new Operations(client);
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java
index af576c7..aac0e56 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java
@@ -79,7 +79,7 @@ public class ContainerInfo implements Comparable<ContainerInfo> {
     }
 
     public boolean isJBossBased() {
-        return isAS7() || isWildfly() || isEAP();
+        return isAS7() || isWildfly() || isEAP() || getQualifier().toLowerCase().contains("jboss");
     }
 
     @Override
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/CrossDCTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/CrossDCTestEnricher.java
index 3c4e735..fe3ae80 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/CrossDCTestEnricher.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/CrossDCTestEnricher.java
@@ -76,6 +76,10 @@ public class CrossDCTestEnricher {
     static void initializeSuiteContext(SuiteContext suiteContext) {
         Validate.notNull(suiteContext, "Suite context cannot be null.");
         CrossDCTestEnricher.suiteContext = suiteContext;
+
+        if (AuthServerTestEnricher.AUTH_SERVER_CROSS_DC && suiteContext.getCacheServersInfo().isEmpty() && !AuthServerTestEnricher.CACHE_SERVER_LIFECYCLE_SKIP) {
+            throw new IllegalStateException("Cache containers misconfiguration");
+        }
     }
 
     public void beforeTest(@Observes(precedence = -2) Before event) {
@@ -160,33 +164,6 @@ public class CrossDCTestEnricher {
         suspendPeriodicTasks();
     }
 
-    private static void initializeTLS(ContainerInfo containerInfo) {
-        if (AuthServerTestEnricher.AUTH_SERVER_SSL_REQUIRED) {
-            log.infof("\n\n### Setting up TLS for %s ##\n\n", containerInfo);
-            try {
-                OnlineManagementClient client = getManagementClient(containerInfo);
-                AuthServerTestEnricher.enableTLS(client);
-                client.close();
-            } catch (Exception e) {
-                log.warn("Failed to set up TLS. This may lead to unexpected behavior unless the test" +
-                      " sets it up manually", e);
-            }
-
-        }
-    }
-
-    private static OnlineManagementClient getManagementClient(ContainerInfo containerInfo) {
-        try {
-            return ManagementClient.online(OnlineOptions
-                  .standalone()
-                  .hostAndPort("localhost", Integer.valueOf(containerInfo.getProperties().get("managementPort")))
-                  .build()
-            );
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     public void afterTest(@Observes After event) {
         if (!suiteContext.isAuthServerCrossDc()) return;
 
@@ -205,11 +182,13 @@ public class CrossDCTestEnricher {
           .map(StopContainer::new)
           .forEach(stopContainer::fire);
 
-        DC.validDcsStream()
-          .map(CrossDCTestEnricher::getCacheServer)
-          .map(ContainerInfo::getArquillianContainer)
-          .map(StopContainer::new)
-          .forEach(stopContainer::fire);
+        if (!AuthServerTestEnricher.CACHE_SERVER_LIFECYCLE_SKIP) {
+            DC.validDcsStream()
+                    .map(CrossDCTestEnricher::getCacheServer)
+                    .map(ContainerInfo::getArquillianContainer)
+                    .map(StopContainer::new)
+                    .forEach(stopContainer::fire);
+        }
     }
 
     public void stopSuiteContainers(@Observes(precedence = 4) StopSuiteContainers event) {
@@ -292,6 +271,8 @@ public class CrossDCTestEnricher {
     }
 
     public static void startCacheServer(DC dc) {
+        if (AuthServerTestEnricher.CACHE_SERVER_LIFECYCLE_SKIP) return;
+
         if (!containerController.get().isStarted(getCacheServer(dc).getQualifier())) {
             log.infof("--DC: Starting %s", getCacheServer(dc).getQualifier());
             containerController.get().start(getCacheServer(dc).getQualifier());
@@ -300,6 +281,8 @@ public class CrossDCTestEnricher {
     }
 
     public static void stopCacheServer(DC dc) {
+        if (AuthServerTestEnricher.CACHE_SERVER_LIFECYCLE_SKIP) return;
+
         String qualifier = getCacheServer(dc).getQualifier();
 
         if (containerController.get().isStarted(qualifier)) {
@@ -359,7 +342,7 @@ public class CrossDCTestEnricher {
         if (! containerInfo.isStarted()) {
             log.infof("--DC: Starting backend auth-server node: %s", containerInfo.getQualifier());
             containerController.get().start(containerInfo.getQualifier());
-            initializeTLS(containerInfo);
+            AuthServerTestEnricher.initializeTLS(containerInfo);
             createRESTClientsForNode(containerInfo);
         }
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
index 0516b03..1fab946 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
@@ -8,6 +8,7 @@ import org.keycloak.admin.client.Keycloak;
 import org.keycloak.models.Constants;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
 import org.keycloak.testsuite.arquillian.ContainerInfo;
 import org.keycloak.testsuite.arquillian.undertow.TLSUtils;
 import org.keycloak.testsuite.client.KeycloakTestingClient;
@@ -108,6 +109,9 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
             assertTrue(controller.isStarted(node.getQualifier()));
         }
         log.info("Backend node " + node + " is started");
+
+        AuthServerTestEnricher.initializeTLS(node);
+
         if (!backendAdminClients.containsKey(node)) {
             backendAdminClients.put(node, createAdminClientFor(node));
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
index 2f6b171..2c9368f 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
@@ -327,7 +327,9 @@
                 <property name="adapterImplClass">org.keycloak.testsuite.arquillian.undertow.KeycloakOnUndertow</property>
                 <property name="bindAddress">localhost</property>
                 <property name="bindHttpPort">${auth.server.http.port}</property>
+                <property name="bindHttpsPort">${auth.server.https.port}</property>
                 <property name="bindHttpPortOffset">-79</property>
+                <property name="bindHttpsPortOffset">-79</property>
                 <property name="remoteMode">${undertow.remote}</property>
                 <property name="dataCenter">0</property>
                 <property name="keycloakConfigPropertyOverrides">{