keycloak-aplcache

Merge pull request #1629 from tkyjovsk/master-squashed Updates

9/18/2015 10:12:12 AM

Changes

pom.xml 10(+8 -2)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/account/AccountManagementTest.java 121(+0 -121)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/AbstractTest.java 91(+0 -91)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/fragment/Navigation.java 162(+0 -162)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/model/Account.java 93(+0 -93)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/model/Client.java 104(+0 -104)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/model/Role.java 72(+0 -72)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/model/User.java 146(+0 -146)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/account/PasswordPage.java 82(+0 -82)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/RegisterPage.java 99(+0 -99)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/ClientPage.java 134(+0 -134)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/DefaultRolesPage.java 55(+0 -55)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/PasswordPolicyPage.java 71(+0 -71)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/RolesPage.java 118(+0 -118)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/SecurityPage.java 109(+0 -109)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/user/RoleMappingsPage.java 71(+0 -71)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/user/UserPage.java 204(+0 -204)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/client/AddNewClientTest.java 109(+0 -109)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/role/AddNewRoleTest.java 92(+0 -92)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/settings/ThemesSettingsTest.java 56(+0 -56)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/user/AddNewUserTest.java 119(+0 -119)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/user/RoleMappingsTest.java 72(+0 -72)

testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/login/RegisterNewUserTest.java 136(+0 -136)

testsuite/integration-arquillian/src/test/resources/arquillian.xml 23(+0 -23)

Details

pom.xml 10(+8 -2)

diff --git a/pom.xml b/pom.xml
index 24e5785..054a034 100755
--- a/pom.xml
+++ b/pom.xml
@@ -1332,7 +1332,6 @@
             <id>distribution</id>
             <modules>
                 <module>distribution</module>
-                <module>testsuite/integration-arquillian</module>
             </modules>
         </profile>
 
@@ -1341,7 +1340,6 @@
             <modules>
                 <module>docbook</module>
                 <module>distribution</module>
-                <module>testsuite/integration-arquillian</module>
             </modules>
         </profile>
 
@@ -1364,6 +1362,14 @@
             </build>
         </profile>
 
+        <profile>
+            <id>arquillian-integration-tests</id>
+            <modules>
+                <module>distribution</module>
+                <module>testsuite/integration-arquillian</module>
+            </modules>
+        </profile>
+
         <!-- Configure the JBoss Early Access Maven repository -->
         <profile>
             <id>jboss-earlyaccess-repository</id>
diff --git a/testsuite/integration-arquillian/pom.xml b/testsuite/integration-arquillian/pom.xml
index 2ef2ac3..064e065 100644
--- a/testsuite/integration-arquillian/pom.xml
+++ b/testsuite/integration-arquillian/pom.xml
@@ -2,190 +2,44 @@
 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <parent>
-        <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-testsuite-pom</artifactId>
         <version>1.6.0.Final-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>keycloak-testsuite-integration-arquillian</artifactId>
-    <name>KeyCloak Arquillian TestSuite</name>
-
-    <properties>
-        <browser>phantomjs</browser>
-		
-        <arquillian-core.version>1.1.5.Final</arquillian-core.version>
-        <selenium.version>2.45.0</selenium.version>
-        <arquillian-drone.version>1.3.1.Final</arquillian-drone.version>
-        <arquillian-phantomjs.version>1.1.4.Final</arquillian-phantomjs.version>
-        <arquillian-graphene.version>2.0.3.Final</arquillian-graphene.version>
-        <arquillian-wildfly-container.version>8.1.0.Final</arquillian-wildfly-container.version>
-        
-        <!-- Used in profile "wildfly-8-remote".
-        Set to "false" if admin password has already been updated after first login. -->
-        <firstAdminLogin>true</firstAdminLogin>
-    </properties>
-
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.jboss.arquillian.selenium</groupId>
-                <artifactId>selenium-bom</artifactId>
-                <version>${selenium.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.jboss.arquillian</groupId>
-                <artifactId>arquillian-bom</artifactId>
-                <version>${arquillian-core.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.jboss.arquillian.extension</groupId>
-                <artifactId>arquillian-drone-bom</artifactId>
-                <version>${arquillian-drone.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.wildfly</groupId>
-                <artifactId>wildfly-arquillian-container-remote</artifactId>
-                <version>${arquillian-wildfly-container.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.wildfly</groupId>
-                <artifactId>wildfly-arquillian-container-managed</artifactId>
-                <version>${arquillian-wildfly-container.version}</version>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-
-    <dependencies>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.jboss.arquillian.junit</groupId>
-            <artifactId>arquillian-junit-container</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.jboss.arquillian.graphene</groupId>
-            <artifactId>graphene-webdriver</artifactId>
-            <version>${arquillian-graphene.version}</version>
-            <type>pom</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.jboss.arquillian.extension</groupId>
-            <artifactId>arquillian-phantom-driver</artifactId>
-            <version>${arquillian-phantomjs.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-server-dist</artifactId>
-            <scope>test</scope>
-            <type>zip</type>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-        </dependency>
-    </dependencies>
-
-    <profiles>
-        <profile>
-            <id>wildfly-8-remote</id>
-            <dependencies>
-                <dependency>
-                    <groupId>org.wildfly</groupId>
-                    <artifactId>wildfly-arquillian-container-remote</artifactId>
-                    <scope>test</scope>
-                </dependency>
-            </dependencies>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <systemPropertyVariables>
-                                <shouldDeploy>false</shouldDeploy>
-                                <arquillian.launch>wildfly-8-remote</arquillian.launch>
-                                <browser>${browser}</browser>
-                                <firstAdminLogin>${first.login}</firstAdminLogin>
-                            </systemPropertyVariables>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-		
-        <profile>
-            <id>wildfly-8-managed</id>
-            <activation>
-                <activeByDefault>true</activeByDefault>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.wildfly</groupId>
-                    <artifactId>wildfly-arquillian-container-managed</artifactId>
-                    <scope>test</scope>
-                </dependency>
-            </dependencies>
-            <properties>
-                <install.directory>${project.build.directory}/install</install.directory>
-                <jbossHome>${install.directory}/keycloak-${project.version}</jbossHome>
-            </properties>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-dependency-plugin</artifactId>
-                        <version>2.10</version>
-                        <executions>
-                            <execution>
-                                <id>unpack</id>
-                                <phase>process-test-resources</phase>
-                                <goals>
-                                    <goal>unpack</goal>
-                                </goals>
-                                <configuration>
-                                    <artifactItems>
-                                        <artifactItem>
-                                            <groupId>org.keycloak</groupId>
-                                            <artifactId>keycloak-server-dist</artifactId>
-                                            <type>zip</type>
-                                            <overWrite>false</overWrite>
-                                        </artifactItem>
-                                    </artifactItems>
-                                    <outputDirectory>${install.directory}</outputDirectory>
-                                    <overWriteReleases>false</overWriteReleases>
-                                    <overWriteSnapshots>true</overWriteSnapshots>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <systemPropertyVariables>
-                                <shouldDeploy>false</shouldDeploy>
-                                <arquillian.launch>wildfly-8-managed</arquillian.launch>
-                                <browser>${browser}</browser>
-                                <jbossHome>${jbossHome}</jbossHome>
-                            </systemPropertyVariables>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-    </profiles>
+    
+    <groupId>org.keycloak.testsuite</groupId>
+    <artifactId>integration-arquillian</artifactId>
+    <packaging>pom</packaging>
+    <name>Keycloak Integration TestSuite with Arquillian</name>
+    
+    <modules>
+        <module>servers</module>
+        <module>tests</module>
+    </modules>
+    
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>2.18.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>xml-maven-plugin</artifactId>
+                    <version>1.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <version>2.10</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+    
+    
 </project>
diff --git a/testsuite/integration-arquillian/README.md b/testsuite/integration-arquillian/README.md
index a81701d..7620d98 100644
--- a/testsuite/integration-arquillian/README.md
+++ b/testsuite/integration-arquillian/README.md
@@ -1,21 +1,61 @@
-Testing admin console with Arquillian
-=====================================
+# Keycloak Integration Testsuite with Arquillian
 
-There are currently two ways of running the tests with help of Arquillian.
+## Structure
 
-Remote mode
-----------
+```
+integration-arquillian
+│
+├──servers  (submodules enabled via profiles)
+│  ├──wildfly
+│  └──eap6
+│
+└──tests
+   ├──base
+   └──adapters  (submodules enabled via profiles, all depend on base)
+      ├──wildfly
+      ├──wildfly-relative  (needs servers/wildfly)
+      ├──wildfly8
+      ├──as7
+      ├──tomcat
+      └──karaf
 
-Just simply typle `mvn verify` and you are all set. This requires the instance of Wildfly with embedded Keycloak to be already running.
+```
 
-Managed mode
-------------
+## General Concepts
 
-You need to pass two arguments to Maven, first is location of your Wildfly server with embedded Keycloak and the other is name of the profile.
+The testsuite supports **multiple server runtimes** for the Keycloak server.
+The **default is Undertow** which is the fastest and easiest option, and runs in the same JVM as the tests.
 
-    mvn verify -Pwildfly-8-managed -DjbossHome=/your/server/location
+Other options are **Wildfly 9** and **EAP 6**. These have some additional requirements and limitations:
+1. The selected server module must be built before any tests can be run. 
+All server-side configuration is done during this build (e.g. datasource configuration).
+Once server artifact is built the tests modules can unpack it via `maven-dependency-plugin` into their working directory before running.
+2. Before the selected server module can be built the `keycloak/distribution` module also needs to be built.
 
-Browser
--------
+### Server Runtimes
 
-There are currently two supported browsers - PhantomJS and Firefox. PhantomJS is the default one, in order to use Firefox just specify `-Dbrowser=firefox` parameter in the Maven command. 
+TODO: explain why separate module, list config options, note on migration modules
+
+### Base Testsuite
+
+login flows + account management
+
+admin ui
+
+abstract adapter tests
+
+### Adapter Tests
+
+test servlets: demo, session
+
+examples
+
+## Running the Tests
+
+### Undertow
+
+### Wildfly or EAP 6
+
+### Adapters
+
+### Supported Browsers
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/README_old.md b/testsuite/integration-arquillian/README_old.md
new file mode 100644
index 0000000..76357ce
--- /dev/null
+++ b/testsuite/integration-arquillian/README_old.md
@@ -0,0 +1,189 @@
+# Keycloak Integration Testsuite with Arquillian
+
+*OUT OF DATE - NEEDS REWRITE*
+
+## Usage
+
+Running the tests: `mvn test` or `mvn clean test`
+
+## Test suite
+
+### Selecting container for Keycloak Server
+
+The testsuite requires a container for Keycloak Server to be selected.
+This container is used by all tests in the suite during a single test execution.
+
+*By default* the tests run with server on embedded *Undertow*.
+A different container can be selected with profile, e.g. `-Pauth-server-wildfly`.
+
+### Containers Supported for Keycloak Server
+
+| Container | Arquillian Qualifier | Maven | Dependencies |
+| --- | --- | --- | --- |
+| **Undertow** | `auth-server-undertow` | **default** | `undertow-core`, `resteasy-undertow` |
+| **Wildfly 9** | `auth-server-wildfly` | `-Pauth-server-wildfly` | `keycloak-server-dist` or `wildfly-dist`+`keycloak-server-overlay` |
+| **EAP 6.4** | `auth-server-eap6` | `-Pauth-server-eap6` | `keycloak-server-dist` or `eap6-dist`+`keycloak-server-overlay` |
+
+See the relevant container definitions in `arquillian.xml` located in the **test resources** folder.
+
+### Test Class Hierarchy
+```
+AbstractKeycloakTest
+├── AbstractAdminConsoleTest
+└── AbstractAdapterTest
+```
+
+### AbstractKeycloakTest
+
+Handles test realms. Provides Admin Client for REST operations.
+
+* **@BeforeClass**
+ 1. Updates the admin password to enable the admin user.
+* **@Before**
+ 1. Initiates admin client
+ 2. Imports test realms. (Loading test realms is overriden in subclasses.)
+* **@After**
+ 1. Removes test realms.
+ 2. Closes admin client.
+
+### ContainersTestEnricher
+
+Manages *container lifecycles*.
+
+`ContainersTestEnricher` is a custom Arquillian observer that handles lifecycles of auth server and app server containers for each test class.
+Containers are started during `@BeforeClass` and shut down during `@AfterClass` event.
+
+*Optionally* each test class can be annotated with `@AuthServerContainer("qualifier")` and `@AppServerConatiner("qualifier")` annotations 
+to indicate containers required for the test.
+
+* In case `@AuthServerContainer` is not present the *auth server qualifier* is loaded from `auth.server.container` property.
+* In case `@AppServerContainer` is not present or it's value is the same as *auth server qualifier*, the app server isn't started for the test class.
+
+## Admin Console Tests
+
+Tests for admin console are located in `org/keycloak/testsuite/console`.
+Related non-test classes are located on the same path in the **main sources**.
+
+Admin console tests are **ENABLED by default**. They can be disabled by `-P no-console`.
+
+
+## Adapter Tests
+
+Adapter tests are located in `org/keycloak/testsuite/adapter`.
+Related non-test classes can be found on the same path in the **main sources**.
+
+Adapter tests are **DISABLED by default**. They can be enabled by profiles.
+Multiple profiles can be enabled for a single test execution.
+
+*Note:* When testing adapter with multiple containers in a single run it is better 
+to use the `--fail-at-end` (`-fae`) strategy instead of the default `--fail-fast` one.
+This will allow Maven to continue building other modules even if some of them have test failures.
+
+### Containers Supported for Adapter Tests
+
+| Container | Arquillian Qualifier | Maven | Dependencies |
+| --- | --- | --- | --- |
+| **Wildfly 9** Relative | `auth-server-wildfly` | `-Pauth-server-wildfly` | `keycloak-server-dist` or `wildfly-dist`+`keycloak-server-overlay`, `keycloak-adapter-dist-wf9` |
+| **Wildfly 9** | `app-server-wildfly` | `-Papp-server-wildfly` | `wildfly-dist`, `keycloak-adapter-dist-wf9` |
+| **Wildfly 8** | `app-server-wildfly` | `-Papp-server-wildfly8` | `wildfly-dist:8.2.1.Final`, `keycloak-adapter-dist-wf8` |
+| **JBoss AS 7** | `app-server-as7` | `-Papp-server-as7` | `jboss-as-dist`, `keycloak-adapter-dist-as7` |
+| **Tomcat 8** | `app-server-tomcat` | `-Papp-server-tomcat` | `tomcat`, `keycloak-tomcat8-adapter-dist` |
+| **Karaf 3** | `app-server-karaf` | `-Papp-server-karaf` | `apache-camel`, `apache-cxf`, `keycloak-osgi-features`, `keycloak-fuse-example-features` |
+
+See the relevant container definitions in `tests/adapter/<container>/src/main/xslt/arquillian.xsl`.
+
+***Important:*** Arquillian cannot load multiple controllers for JBossAS/Wildfly containers in a single run (because same class name)
+but a different controller is required for JBossAS7/EAP6 than for WF8/9. Because of this:
+
+ - Adapter tests for *Wildfly 8/9* cannot be run against server on *EAP 6*. `-Papp-server-wildfly*` ⇒ `!auth-server-eap6`
+ - Adapter tests for *JBossAS 7* can only be run against server on *EAP 6*. `-Papp-server-as7,auth-server-eap6`
+
+### Adapter Test Types
+
+1. Using **test servlets**.
+2. Using **example/demo wars**.
+
+```
+AbstractKeycloakTest
+└── AbstractAdapterTest
+    ├── AbstractServletsAdapterTest
+    |   ├── Relative…
+    |   ├── Wildfly…
+    |   ├── Tomcat…
+    |   …
+    └── AbstractExampleAdapterTest
+        ├── AbstractDemoExampleAdapterTest
+        |   ├── Relative…
+        |   ├── Wildfly…
+        |   ├── Tomcat…
+        |   …
+        ├── AbstractBasicAuthExampleAdapterTest
+        |   ├── Relative…
+        |   ├── Wildfly…
+        |   ├── Tomcat…
+        |   …
+        …
+```
+
+### Relative vs Non-relative scenario
+
+The test suite can handle both types.
+It automatically modifies imported test realms and deployments' adapter configs based on scenario type.
+
+| Scenario | Description | Realm config (server side) | Adapter config (client side) |
+| --- | --- | --- | --- |
+| **Relative** | Both Keycloak Server and test apps running in the same container. | client `baseUrl`, `adminUrl` and `redirect-uris` can be relative | `auth-server-url` can be relative |
+| **Non-relative** | Test apps run in a different container than Keycloak Server. | client `baseUrl`, `adminUrl` and `redirect-uris` need to include FQDN of the app server | `auth-server-url` needs to include FQDN of the auth server|
+
+### Adapter Libraries Mode
+
+1. **Provided.** By container, e.g. as a subsystem. *Default.*
+2. **Bundled.** In the deployed war in `/WEB-INF/libs`. Enable with `-Dadapter.libs.bundled`. *Wildfly only*.
+
+### Adapter Config Mode
+
+1. ~~**Provided.** In `standalone.xml` using `secure-deployment`. *Wildfly only.*~~ WIP
+2. **Bundled.** In the deployed war in `/WEB-INF/keycloak.json`. *Default.*
+
+### Adapters Test Coverage
+
+| Module | Coverage | Supported Containers |
+| --- | --- | --- |
+| ***Test Servlets*** | Good | All |
+| **Demo** | Minimal, WIP | `auth-server-wildfly` (relative) |
+| **Admin Client** |  |
+| **Cordova** |  |
+| **CORS** |  |
+| **JS Console** | Good | `auth-server-wildfly` (relative) |
+| **Providers** |  |
+| Themes |  |
+| Multitenancy | WIP |  |
+| **Basic Auth** | Good | All |
+| **Fuse** | Good | `app-server-karaf` |
+| SAML |  |
+| LDAP |  |
+| Kerberos |  |
+
+## Supported Browsers
+
+| Browser | Maven |
+| --- | --- | 
+| **PhantomJS** | `-Dbrowser=phantomjs` **default** |
+| **Firefox** | `-Dbrowser=firefox` |
+
+
+## Custom Arquillian Extensions
+
+Custom extensions are registered in `META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension`.
+
+* Multiple containers extension
+ * Replaces Arquillian's default container handling.
+ * Allows to manage multiple container instances of different types within a single test run.
+ * Allows to skip loading disabled containers based on `enabled` config property in `arquillian.xml`.
+* Custom extension
+ * `ContainersTestEnricher` - Handles lifecycles of auth-server and app-server.
+ * `CustomUndertowContainer` - A custom container controller for JAX-RS-enabled Undertow with Keycloak Server.
+ * `DeploymentArchiveProcessor` - Modifies adapter config before deployment on app server based on relative/non-relative scenario.
+ * `URLProvider` - Fixes URLs injected by Arquillian which contain 127.0.0.1 instead of localhost.
+ * `JiraTestExecutionDecider` - Skipping tests for unresolved JIRAs.
+
diff --git a/testsuite/integration-arquillian/servers/eap6/assembly.xml b/testsuite/integration-arquillian/servers/eap6/assembly.xml
new file mode 100644
index 0000000..537dd4e
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+    
+    <id>auth-server-eap6</id>
+
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-${project.version}</outputDirectory>
+            <excludes>
+                <exclude>**/*.sh</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-${project.version}</outputDirectory>
+            <includes>
+                <include>**/*.sh</include>
+            </includes>
+            <fileMode>0755</fileMode>
+        </fileSet>
+    </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/eap6/pom.xml b/testsuite/integration-arquillian/servers/eap6/pom.xml
new file mode 100644
index 0000000..4bab815
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/pom.xml
@@ -0,0 +1,184 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-servers</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-server-eap6</artifactId>
+    <packaging>pom</packaging>
+    <name>Server on EAP 6</name>
+    
+    <properties>
+        <keycloak.server.home>${project.build.directory}/unpacked/jboss-eap-6.4</keycloak.server.home>
+    </properties>
+            
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.as</groupId>
+            <artifactId>jboss-as-dist</artifactId>
+            <version>${jboss.version}</version>
+            <type>zip</type>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-overlay-eap6</artifactId>
+            <version>${project.version}</version>
+            <type>zip</type>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-eap6-adapter-dist</artifactId>
+            <type>zip</type>
+        </dependency>
+    </dependencies>
+            
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>            
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack-eap6-and-server-overlay</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.jboss.as</groupId>
+                                    <artifactId>jboss-as-dist</artifactId>
+                                    <version>${jboss.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-server-overlay-eap6</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${keycloak.server.home}</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>move-standalone-keycloak-xml</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                        <configuration>
+                            <tasks>
+                                <move file="${keycloak.server.home}/standalone/configuration/standalone-keycloak.xml" 
+                                      tofile="${keycloak.server.home}/standalone/configuration/standalone.xml"/>
+                            </tasks>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>create-zip</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>assembly.xml</descriptor>
+                            </descriptors>
+                            <appendAssemblyId>false</appendAssemblyId>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <profiles>
+        <profile>
+            <id>adapter-libs-provided</id>
+            <activation>    
+                <property>
+                    <name>!adapter.libs.bundled</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unpack-adapter</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.keycloak</groupId>
+                                            <artifactId>keycloak-eap6-adapter-dist</artifactId>
+                                            <version>${project.version}</version>
+                                            <type>zip</type>
+                                            <outputDirectory>${keycloak.server.home}</outputDirectory>
+                                        </artifactItem>
+                                    </artifactItems>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>configure-adapter-subsystem</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>transform</goal>
+                                </goals>
+                                <configuration>
+                                    <transformationSets>
+                                        <transformationSet>
+                                            <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                            <includes>
+                                                <include>standalone.xml</include>
+                                            </includes>
+                                            <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+                                            <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                        </transformationSet>
+                                    </transformationSets>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+            
+</project>
diff --git a/testsuite/integration-arquillian/servers/eap6/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:3.0"
+                xmlns:ds="urn:jboss:domain:datasources:3.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+    
+    <!-- Remove keycloak datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+                         /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+    </xsl:template>
+    
+    <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+    <xsl:param name="driver" select="'h2'"/>
+    
+    <xsl:param name="username" select="'sa'"/>
+    <xsl:param name="password" select="'sa'"/>
+    
+    <xsl:param name="min.poolsize" select="'10'"/>
+    <xsl:param name="max.poolsize" select="'50'"/>
+    <xsl:param name="pool.prefill" select="'true'"/>
+    
+    <xsl:variable name="newDatasourceDefinition">
+        <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+            <connection-url>
+                <xsl:value-of select="$jdbc.url"/>
+            </connection-url>
+            <driver>
+                <xsl:value-of select="$driver"/>
+            </driver>
+            <security>
+                <user-name>
+                    <xsl:value-of select="$username"/>
+                </user-name>
+                <password>
+                    <xsl:value-of select="$password"/>
+                </password>
+            </security>
+            <pool>
+                <min-pool-size>
+                    <xsl:value-of select="$min.poolsize"/>
+                </min-pool-size>
+                <max-pool-size>
+                    <xsl:value-of select="$max.poolsize"/>
+                </max-pool-size>
+                <prefill>
+                    <xsl:value-of select="$pool.prefill"/>
+                </prefill>
+            </pool>
+        </datasource>
+    </xsl:variable>
+    
+    <xsl:variable name="newDriverDefinition">
+        <xsl:if test="$driver != 'h2'">
+            <driver name="{$driver}" module="com.{$driver}" />
+        </xsl:if>
+    </xsl:variable>
+    
+    <!-- Add new datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDatasourceDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Add new driver definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDriverDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Copy everything else. -->
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/eap6/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:m="urn:jboss:module:1.3"
+                version="2.0"
+                exclude-result-prefixes="xalan m">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+    
+       
+    <xsl:param name="database" select="''"/>
+    <xsl:param name="version" select="''"/>
+    
+    <xsl:variable name="newModuleDefinition">
+        <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+            <resources>
+                <resource-root path="{$database}-{$version}.jar"/>
+            </resources>
+            <dependencies>
+                <module name="javax.api"/>
+                <module name="javax.transaction.api"/>
+            </dependencies>
+        </module>
+    </xsl:variable>
+    
+    <!-- clear whole document -->
+    <xsl:template match="/*" />
+    
+    <!-- Copy new module definition. -->
+    <xsl:template match="/*">
+        <xsl:copy-of select="$newModuleDefinition"/>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/eap6/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..4ffc2c6
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:1.7"
+                xmlns:ds="urn:jboss:domain:datasources:1.2"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.1"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:param name="config"/>
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="//j:extensions">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//j:profile">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//sec:security-domains">
+        <xsl:copy>
+            <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+            <security-domain name="keycloak">
+                <authentication>
+                    <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+            <security-domain name="sp" cache-type="default">
+                <authentication>
+                    <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/pom.xml b/testsuite/integration-arquillian/servers/pom.xml
new file mode 100644
index 0000000..254e40e
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-servers</artifactId>
+    <packaging>pom</packaging>
+    <name>Servers</name>
+
+    <profiles>
+        <profile>
+            <id>auth-server-wildfly</id>
+            <modules>
+                <module>wildfly</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>auth-server-eap6</id>
+            <modules>
+                <!--doesn't work yet, WIP-->
+                <module>eap6</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>migration-kc14</id>
+            <modules>
+                <module>wildfly_kc14</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>migration-kc13</id>
+            <modules>
+                <module>wildfly_kc13</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>migration-kc12</id>
+            <modules>
+                <module>wildfly_kc12</module>
+            </modules>
+        </profile>
+    </profiles>    
+
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly/assembly.xml b/testsuite/integration-arquillian/servers/wildfly/assembly.xml
new file mode 100644
index 0000000..bfcad35
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+    
+    <id>auth-server-wildfly</id>
+
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-${project.version}</outputDirectory>
+            <excludes>
+                <exclude>**/*.sh</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-${project.version}</outputDirectory>
+            <includes>
+                <include>**/*.sh</include>
+            </includes>
+            <fileMode>0755</fileMode>
+        </fileSet>
+    </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/wildfly/pom.xml b/testsuite/integration-arquillian/servers/wildfly/pom.xml
new file mode 100644
index 0000000..e2b91e7
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/pom.xml
@@ -0,0 +1,372 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-servers</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-server-wildfly</artifactId>
+    <packaging>pom</packaging>
+    <name>Server on Wildfly</name>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>            
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>create-zip</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>assembly.xml</descriptor>
+                            </descriptors>
+                            <appendAssemblyId>false</appendAssemblyId>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <profiles>
+        <profile>
+            <id>server-overlay</id>
+            <activation>
+                <property>
+                    <name>server-overlay</name>
+                </property>
+            </activation>
+            <properties>
+                <keycloak.server.home>${project.build.directory}/unpacked/wildfly-${wildfly.version}</keycloak.server.home>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unpack-wildfly-and-server-overlay</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.wildfly</groupId>
+                                            <artifactId>wildfly-dist</artifactId>
+                                            <version>${wildfly.version}</version>
+                                            <type>zip</type>
+                                            <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+                                        </artifactItem>
+                                        <artifactItem>
+                                            <groupId>org.keycloak</groupId>
+                                            <artifactId>keycloak-server-overlay</artifactId>
+                                            <version>${project.version}</version>
+                                            <type>zip</type>
+                                            <outputDirectory>${keycloak.server.home}</outputDirectory>
+                                        </artifactItem>
+                                    </artifactItems>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <version>1.8</version>
+                        <executions>
+                            <execution>
+                                <id>move-standalone-keycloak-xml</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <tasks>
+                                        <move file="${keycloak.server.home}/standalone/configuration/standalone-keycloak.xml" 
+                                              tofile="${keycloak.server.home}/standalone/configuration/standalone.xml"/>
+                                    </tasks>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        
+        <profile>
+            <id>server-dist</id>
+            <activation>
+                <property>
+                    <name>!server-overlay</name>
+                </property>
+            </activation>
+            <properties>
+                <keycloak.server.home>${project.build.directory}/unpacked/keycloak-${project.version}</keycloak.server.home>
+            </properties>
+            <dependencies>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-server-dist</artifactId>
+                    <type>zip</type>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unpack-server</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.keycloak</groupId>
+                                            <artifactId>keycloak-server-dist</artifactId>
+                                            <version>${project.version}</version>
+                                            <type>zip</type>
+                                            <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+                                        </artifactItem>
+                                    </artifactItems>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        
+        <profile>
+            <id>adapter-libs-provided</id>
+            <activation>    
+                <property>
+                    <name>!adapter.libs.bundled</name>
+                </property>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-wf9-adapter-dist</artifactId>
+                    <type>zip</type>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unpack-adapter</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.keycloak</groupId>
+                                            <artifactId>keycloak-wf9-adapter-dist</artifactId>
+                                            <version>${project.version}</version>
+                                            <type>zip</type>
+                                            <outputDirectory>${keycloak.server.home}</outputDirectory>
+                                        </artifactItem>
+                                    </artifactItems>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>configure-adapter-subsystem</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>transform</goal>
+                                </goals>
+                                <configuration>
+                                    <transformationSets>
+                                        <transformationSet>
+                                            <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                            <includes>
+                                                <include>standalone.xml</include>
+                                            </includes>
+                                            <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+                                            <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                        </transformationSet>
+                                    </transformationSets>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>jpa</id>
+            <properties>
+                <jdbc.mvn.driver.deployment.dir>${keycloak.server.home}/modules/system/layers/base/com/${jdbc.mvn.artifactId}/main</jdbc.mvn.driver.deployment.dir>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-enforcer-plugin</artifactId>
+                        <version>1.4</version>
+                        <executions>
+                            <execution>
+                                <id>enforce-properties</id>
+                                <goals>
+                                    <goal>enforce</goal>
+                                </goals>
+                                <configuration>
+                                    <rules>
+                                        <requireProperty>
+                                            <property>jdbc.mvn.groupId</property>
+                                        </requireProperty>
+                                        <requireProperty>
+                                            <property>jdbc.mvn.artifactId</property>
+                                        </requireProperty>
+                                        <requireProperty>
+                                            <property>jdbc.mvn.version</property>
+                                        </requireProperty>
+                                        <requireProperty>
+                                            <property>keycloak.connectionsJpa.url</property>
+                                        </requireProperty>
+                                        <requireProperty>
+                                            <property>keycloak.connectionsJpa.user</property>
+                                        </requireProperty>
+                                        <requireProperty>
+                                            <property>keycloak.connectionsJpa.password</property>
+                                        </requireProperty>
+                                    </rules>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>jdbc-driver</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>copy</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>${jdbc.mvn.groupId}</groupId>
+                                            <artifactId>${jdbc.mvn.artifactId}</artifactId>        
+                                            <version>${jdbc.mvn.version}</version>
+                                            <type>jar</type>
+                                        </artifactItem>
+                                    </artifactItems>
+                                    <outputDirectory>${jdbc.mvn.driver.deployment.dir}</outputDirectory>
+                                    <overWriteIfNewer>true</overWriteIfNewer>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>configure-wildfly-datasource</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>transform</goal>
+                                </goals>
+                                <configuration>
+                                    <transformationSets>
+                                        <!-- create module.xml in modules -->
+                                        <transformationSet>
+                                            <dir>${keycloak.server.home}/modules/system/layers/base/com/h2database/h2/main</dir>
+                                            <stylesheet>src/main/xslt/module.xsl</stylesheet>
+                                            <includes>
+                                                <include>module.xml</include>
+                                            </includes>
+                                            <outputDir>${jdbc.mvn.driver.deployment.dir}</outputDir>
+                                            <parameters>
+                                                <parameter>
+                                                    <name>database</name>
+                                                    <value>${jdbc.mvn.artifactId}</value>
+                                                </parameter>
+                                                <parameter>
+                                                    <name>version</name>
+                                                    <value>${jdbc.mvn.version}</value>
+                                                </parameter>
+                                            </parameters>
+                                        </transformationSet>
+                                        <!-- add datasource to standalone.xml -->
+                                        <transformationSet>
+                                            <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                            <stylesheet>src/main/xslt/datasource.xsl</stylesheet>
+                                            <includes>
+                                                <include>standalone.xml</include>
+                                            </includes>
+                                            <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                            <parameters>
+                                                <parameter>
+                                                    <name>jdbc.url</name>
+                                                    <value>${keycloak.connectionsJpa.url}</value>
+                                                </parameter>
+                                                <parameter>
+                                                    <name>driver</name>
+                                                    <value>${jdbc.mvn.artifactId}</value>
+                                                </parameter>
+                                                <parameter>
+                                                    <name>username</name>
+                                                    <value>${keycloak.connectionsJpa.user}</value>
+                                                </parameter>
+                                                <parameter>
+                                                    <name>password</name>
+                                                    <value>${keycloak.connectionsJpa.password}</value>
+                                                </parameter>
+                                            </parameters>
+                                        </transformationSet>
+                                        <!-- add logger for org.hibernate.dialect.Dialect -->
+                                        <transformationSet>
+                                            <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                            <stylesheet>src/main/xslt/add-dialect-logger.xsl</stylesheet>
+                                            <includes>
+                                                <include>standalone.xml</include>
+                                            </includes>
+                                            <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                        </transformationSet>
+                                    </transformationSets>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>        
+    </profiles>
+    
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/add-dialect-logger.xsl b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/add-dialect-logger.xsl
new file mode 100644
index 0000000..b5dc8c4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/add-dialect-logger.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+                xmlns:xalan="http://xml.apache.org/xalan" 
+                version="2.0"
+                exclude-result-prefixes="xalan">
+    
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:logging:'"/>
+
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+                        /*[local-name()='root-logger' and starts-with(namespace-uri(), $nsDS)]">
+        <logger category="org.hibernate.dialect.Dialect">
+            <level name="ALL"/>
+        </logger>
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+
+    <!-- Copy everything else. -->
+    <xsl:template match="@* | node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()"/>
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:3.0"
+                xmlns:ds="urn:jboss:domain:datasources:3.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+    
+    <!-- Remove keycloak datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+                         /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+    </xsl:template>
+    
+    <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+    <xsl:param name="driver" select="'h2'"/>
+    
+    <xsl:param name="username" select="'sa'"/>
+    <xsl:param name="password" select="'sa'"/>
+    
+    <xsl:param name="min.poolsize" select="'10'"/>
+    <xsl:param name="max.poolsize" select="'50'"/>
+    <xsl:param name="pool.prefill" select="'true'"/>
+    
+    <xsl:variable name="newDatasourceDefinition">
+        <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+            <connection-url>
+                <xsl:value-of select="$jdbc.url"/>
+            </connection-url>
+            <driver>
+                <xsl:value-of select="$driver"/>
+            </driver>
+            <security>
+                <user-name>
+                    <xsl:value-of select="$username"/>
+                </user-name>
+                <password>
+                    <xsl:value-of select="$password"/>
+                </password>
+            </security>
+            <pool>
+                <min-pool-size>
+                    <xsl:value-of select="$min.poolsize"/>
+                </min-pool-size>
+                <max-pool-size>
+                    <xsl:value-of select="$max.poolsize"/>
+                </max-pool-size>
+                <prefill>
+                    <xsl:value-of select="$pool.prefill"/>
+                </prefill>
+            </pool>
+        </datasource>
+    </xsl:variable>
+    
+    <xsl:variable name="newDriverDefinition">
+        <xsl:if test="$driver != 'h2'">
+            <driver name="{$driver}" module="com.{$driver}" />
+        </xsl:if>
+    </xsl:variable>
+    
+    <!-- Add new datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDatasourceDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Add new driver definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDriverDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Copy everything else. -->
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:m="urn:jboss:module:1.3"
+                version="2.0"
+                exclude-result-prefixes="xalan m">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+    
+       
+    <xsl:param name="database" select="''"/>
+    <xsl:param name="version" select="''"/>
+    
+    <xsl:variable name="newModuleDefinition">
+        <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+            <resources>
+                <resource-root path="{$database}-{$version}.jar"/>
+            </resources>
+            <dependencies>
+                <module name="javax.api"/>
+                <module name="javax.transaction.api"/>
+            </dependencies>
+        </module>
+    </xsl:variable>
+    
+    <!-- clear whole document -->
+    <xsl:template match="/*" />
+    
+    <!-- Copy new module definition. -->
+    <xsl:template match="/*">
+        <xsl:copy-of select="$newModuleDefinition"/>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..a483717
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:3.0"
+                xmlns:ds="urn:jboss:domain:datasources:3.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:param name="config"/>
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="//j:extensions">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//j:profile">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//sec:security-domains">
+        <xsl:copy>
+            <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+            <security-domain name="keycloak">
+                <authentication>
+                    <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+            <security-domain name="sp" cache-type="default">
+                <authentication>
+                    <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/assembly.xml b/testsuite/integration-arquillian/servers/wildfly_kc12/assembly.xml
new file mode 100644
index 0000000..b3e9e20
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+    
+    <id>auth-server-wildfly-kc14</id>
+
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-1.2.0.Final</outputDirectory>
+            <excludes>
+                <exclude>**/*.sh</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-1.2.0.Final</outputDirectory>
+            <includes>
+                <include>**/*.sh</include>
+            </includes>
+            <fileMode>0755</fileMode>
+        </fileSet>
+    </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/pom.xml b/testsuite/integration-arquillian/servers/wildfly_kc12/pom.xml
new file mode 100644
index 0000000..2d98af1
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-servers</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-server-wildfly-kc12 </artifactId>
+    <packaging>pom</packaging>
+    <name>Keycloak 1.2.0.Final on Wildfly</name>
+    
+    <properties>
+        <keycloak.server.home>${project.build.directory}/unpacked/keycloak-1.2.0.Final</keycloak.server.home>
+        <jdbc.mvn.driver.deployment.dir>${keycloak.server.home}/modules/system/layers/base/com/${jdbc.mvn.artifactId}/main</jdbc.mvn.driver.deployment.dir>
+    </properties>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>1.4</version>
+                <executions>
+                    <execution>
+                        <id>enforce-properties</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireProperty>
+                                    <property>jdbc.mvn.groupId</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>jdbc.mvn.artifactId</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>jdbc.mvn.version</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.url</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.user</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.password</property>
+                                </requireProperty>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack-server</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-server-dist</artifactId>
+                                    <version>1.2.0.Final</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>jdbc-driver</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>${jdbc.mvn.groupId}</groupId>
+                                    <artifactId>${jdbc.mvn.artifactId}</artifactId>
+                                    <version>${jdbc.mvn.version}</version>
+                                    <type>jar</type>
+                                </artifactItem>
+                            </artifactItems>
+                            <outputDirectory>${jdbc.mvn.driver.deployment.dir}</outputDirectory>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>xml-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>configure-wildfly-datasource</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>transform</goal>
+                        </goals>
+                        <configuration>
+                            <transformationSets>
+                                <!-- create module.xml in modules -->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/modules/system/layers/base/com/h2database/h2/main</dir>
+                                    <stylesheet>src/main/xslt/module.xsl</stylesheet>
+                                    <includes>
+                                        <include>module.xml</include>
+                                    </includes>
+                                    <outputDir>${jdbc.mvn.driver.deployment.dir}</outputDir>
+                                    <parameters>
+                                        <parameter>
+                                            <name>database</name>
+                                            <value>${jdbc.mvn.artifactId}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>version</name>
+                                            <value>${jdbc.mvn.version}</value>
+                                        </parameter>
+                                    </parameters>
+                                </transformationSet>
+                                <!-- add datasource to standalone.xml -->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                    <stylesheet>src/main/xslt/datasource.xsl</stylesheet>
+                                    <includes>
+                                        <include>standalone.xml</include>
+                                    </includes>
+                                    <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                    <parameters>
+                                        <parameter>
+                                            <name>jdbc.url</name>
+                                            <value>${keycloak.connectionsJpa.url}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>driver</name>
+                                            <value>${jdbc.mvn.artifactId}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>username</name>
+                                            <value>${keycloak.connectionsJpa.user}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>password</name>
+                                            <value>${keycloak.connectionsJpa.password}</value>
+                                        </parameter>
+                                    </parameters>
+                                </transformationSet>
+                                <!-- add logger for org.hibernate.dialect.Dialect to standalone.xml-->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                    <stylesheet>src/main/xslt/add-dialect-logger.xsl</stylesheet>
+                                    <includes>
+                                        <include>standalone.xml</include>
+                                    </includes>
+                                    <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                </transformationSet>
+                            </transformationSets>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>create-zip</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>assembly.xml</descriptor>
+                            </descriptors>
+                            <appendAssemblyId>false</appendAssemblyId>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/add-dialect-logger.xsl b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/add-dialect-logger.xsl
new file mode 100644
index 0000000..b5dc8c4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/add-dialect-logger.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+                xmlns:xalan="http://xml.apache.org/xalan" 
+                version="2.0"
+                exclude-result-prefixes="xalan">
+    
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:logging:'"/>
+
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+                        /*[local-name()='root-logger' and starts-with(namespace-uri(), $nsDS)]">
+        <logger category="org.hibernate.dialect.Dialect">
+            <level name="ALL"/>
+        </logger>
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+
+    <!-- Copy everything else. -->
+    <xsl:template match="@* | node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()"/>
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:3.0"
+                xmlns:ds="urn:jboss:domain:datasources:3.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+    
+    <!-- Remove keycloak datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+                         /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+    </xsl:template>
+    
+    <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+    <xsl:param name="driver" select="'h2'"/>
+    
+    <xsl:param name="username" select="'sa'"/>
+    <xsl:param name="password" select="'sa'"/>
+    
+    <xsl:param name="min.poolsize" select="'10'"/>
+    <xsl:param name="max.poolsize" select="'50'"/>
+    <xsl:param name="pool.prefill" select="'true'"/>
+    
+    <xsl:variable name="newDatasourceDefinition">
+        <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+            <connection-url>
+                <xsl:value-of select="$jdbc.url"/>
+            </connection-url>
+            <driver>
+                <xsl:value-of select="$driver"/>
+            </driver>
+            <security>
+                <user-name>
+                    <xsl:value-of select="$username"/>
+                </user-name>
+                <password>
+                    <xsl:value-of select="$password"/>
+                </password>
+            </security>
+            <pool>
+                <min-pool-size>
+                    <xsl:value-of select="$min.poolsize"/>
+                </min-pool-size>
+                <max-pool-size>
+                    <xsl:value-of select="$max.poolsize"/>
+                </max-pool-size>
+                <prefill>
+                    <xsl:value-of select="$pool.prefill"/>
+                </prefill>
+            </pool>
+        </datasource>
+    </xsl:variable>
+    
+    <xsl:variable name="newDriverDefinition">
+        <xsl:if test="$driver != 'h2'">
+            <driver name="{$driver}" module="com.{$driver}" />
+        </xsl:if>
+    </xsl:variable>
+    
+    <!-- Add new datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDatasourceDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Add new driver definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDriverDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Copy everything else. -->
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:m="urn:jboss:module:1.3"
+                version="2.0"
+                exclude-result-prefixes="xalan m">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+    
+       
+    <xsl:param name="database" select="''"/>
+    <xsl:param name="version" select="''"/>
+    
+    <xsl:variable name="newModuleDefinition">
+        <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+            <resources>
+                <resource-root path="{$database}-{$version}.jar"/>
+            </resources>
+            <dependencies>
+                <module name="javax.api"/>
+                <module name="javax.transaction.api"/>
+            </dependencies>
+        </module>
+    </xsl:variable>
+    
+    <!-- clear whole document -->
+    <xsl:template match="/*" />
+    
+    <!-- Copy new module definition. -->
+    <xsl:template match="/*">
+        <xsl:copy-of select="$newModuleDefinition"/>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/assembly.xml b/testsuite/integration-arquillian/servers/wildfly_kc13/assembly.xml
new file mode 100644
index 0000000..08e3ebf
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+    
+    <id>auth-server-wildfly-kc14</id>
+
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-1.3.1.Final</outputDirectory>
+            <excludes>
+                <exclude>**/*.sh</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-1.3.1.Final</outputDirectory>
+            <includes>
+                <include>**/*.sh</include>
+            </includes>
+            <fileMode>0755</fileMode>
+        </fileSet>
+    </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/pom.xml b/testsuite/integration-arquillian/servers/wildfly_kc13/pom.xml
new file mode 100644
index 0000000..58be6cc
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-servers</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-server-wildfly-kc13</artifactId>
+    <packaging>pom</packaging>
+    <name>Keycloak 1.3.1.Final on Wildfly</name>
+    
+    <properties>
+        <keycloak.server.home>${project.build.directory}/unpacked/keycloak-1.3.1.Final</keycloak.server.home>
+        <jdbc.mvn.driver.deployment.dir>${keycloak.server.home}/modules/system/layers/base/com/${jdbc.mvn.artifactId}/main</jdbc.mvn.driver.deployment.dir>
+    </properties>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>1.4</version>
+                <executions>
+                    <execution>
+                        <id>enforce-properties</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireProperty>
+                                    <property>jdbc.mvn.groupId</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>jdbc.mvn.artifactId</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>jdbc.mvn.version</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.url</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.user</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.password</property>
+                                </requireProperty>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack-server</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-server-dist</artifactId>
+                                    <version>1.3.1.Final</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>jdbc-driver</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>${jdbc.mvn.groupId}</groupId>
+                                    <artifactId>${jdbc.mvn.artifactId}</artifactId>
+                                    <version>${jdbc.mvn.version}</version>
+                                    <type>jar</type>
+                                </artifactItem>
+                            </artifactItems>
+                            <outputDirectory>${jdbc.mvn.driver.deployment.dir}</outputDirectory>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>xml-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>configure-wildfly-datasource</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>transform</goal>
+                        </goals>
+                        <configuration>
+                            <transformationSets>
+                                <!-- create module.xml in modules -->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/modules/system/layers/base/com/h2database/h2/main</dir>
+                                    <stylesheet>src/main/xslt/module.xsl</stylesheet>
+                                    <includes>
+                                        <include>module.xml</include>
+                                    </includes>
+                                    <outputDir>${jdbc.mvn.driver.deployment.dir}</outputDir>
+                                    <parameters>
+                                        <parameter>
+                                            <name>database</name>
+                                            <value>${jdbc.mvn.artifactId}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>version</name>
+                                            <value>${jdbc.mvn.version}</value>
+                                        </parameter>
+                                    </parameters>
+                                </transformationSet>
+                                <!-- add datasource to standalone.xml -->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                    <stylesheet>src/main/xslt/datasource.xsl</stylesheet>
+                                    <includes>
+                                        <include>standalone.xml</include>
+                                    </includes>
+                                    <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                    <parameters>
+                                        <parameter>
+                                            <name>jdbc.url</name>
+                                            <value>${keycloak.connectionsJpa.url}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>driver</name>
+                                            <value>${jdbc.mvn.artifactId}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>username</name>
+                                            <value>${keycloak.connectionsJpa.user}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>password</name>
+                                            <value>${keycloak.connectionsJpa.password}</value>
+                                        </parameter>
+                                    </parameters>
+                                </transformationSet>
+                                <!-- add logger for org.hibernate.dialect.Dialect to standalone.xml-->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                    <stylesheet>src/main/xslt/add-dialect-logger.xsl</stylesheet>
+                                    <includes>
+                                        <include>standalone.xml</include>
+                                    </includes>
+                                    <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                </transformationSet>
+                            </transformationSets>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>create-zip</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>assembly.xml</descriptor>
+                            </descriptors>
+                            <appendAssemblyId>false</appendAssemblyId>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/add-dialect-logger.xsl b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/add-dialect-logger.xsl
new file mode 100644
index 0000000..b5dc8c4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/add-dialect-logger.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+                xmlns:xalan="http://xml.apache.org/xalan" 
+                version="2.0"
+                exclude-result-prefixes="xalan">
+    
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:logging:'"/>
+
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+                        /*[local-name()='root-logger' and starts-with(namespace-uri(), $nsDS)]">
+        <logger category="org.hibernate.dialect.Dialect">
+            <level name="ALL"/>
+        </logger>
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+
+    <!-- Copy everything else. -->
+    <xsl:template match="@* | node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()"/>
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:3.0"
+                xmlns:ds="urn:jboss:domain:datasources:3.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+    
+    <!-- Remove keycloak datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+                         /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+    </xsl:template>
+    
+    <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+    <xsl:param name="driver" select="'h2'"/>
+    
+    <xsl:param name="username" select="'sa'"/>
+    <xsl:param name="password" select="'sa'"/>
+    
+    <xsl:param name="min.poolsize" select="'10'"/>
+    <xsl:param name="max.poolsize" select="'50'"/>
+    <xsl:param name="pool.prefill" select="'true'"/>
+    
+    <xsl:variable name="newDatasourceDefinition">
+        <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+            <connection-url>
+                <xsl:value-of select="$jdbc.url"/>
+            </connection-url>
+            <driver>
+                <xsl:value-of select="$driver"/>
+            </driver>
+            <security>
+                <user-name>
+                    <xsl:value-of select="$username"/>
+                </user-name>
+                <password>
+                    <xsl:value-of select="$password"/>
+                </password>
+            </security>
+            <pool>
+                <min-pool-size>
+                    <xsl:value-of select="$min.poolsize"/>
+                </min-pool-size>
+                <max-pool-size>
+                    <xsl:value-of select="$max.poolsize"/>
+                </max-pool-size>
+                <prefill>
+                    <xsl:value-of select="$pool.prefill"/>
+                </prefill>
+            </pool>
+        </datasource>
+    </xsl:variable>
+    
+    <xsl:variable name="newDriverDefinition">
+        <xsl:if test="$driver != 'h2'">
+            <driver name="{$driver}" module="com.{$driver}" />
+        </xsl:if>
+    </xsl:variable>
+    
+    <!-- Add new datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDatasourceDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Add new driver definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDriverDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Copy everything else. -->
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:m="urn:jboss:module:1.3"
+                version="2.0"
+                exclude-result-prefixes="xalan m">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+    
+       
+    <xsl:param name="database" select="''"/>
+    <xsl:param name="version" select="''"/>
+    
+    <xsl:variable name="newModuleDefinition">
+        <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+            <resources>
+                <resource-root path="{$database}-{$version}.jar"/>
+            </resources>
+            <dependencies>
+                <module name="javax.api"/>
+                <module name="javax.transaction.api"/>
+            </dependencies>
+        </module>
+    </xsl:variable>
+    
+    <!-- clear whole document -->
+    <xsl:template match="/*" />
+    
+    <!-- Copy new module definition. -->
+    <xsl:template match="/*">
+        <xsl:copy-of select="$newModuleDefinition"/>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/assembly.xml b/testsuite/integration-arquillian/servers/wildfly_kc14/assembly.xml
new file mode 100644
index 0000000..da4b459
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+    
+    <id>auth-server-wildfly-kc14</id>
+
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-1.4.0.Final</outputDirectory>
+            <excludes>
+                <exclude>**/*.sh</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>${keycloak.server.home}</directory>
+            <outputDirectory>keycloak-1.4.0.Final</outputDirectory>
+            <includes>
+                <include>**/*.sh</include>
+            </includes>
+            <fileMode>0755</fileMode>
+        </fileSet>
+    </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/pom.xml b/testsuite/integration-arquillian/servers/wildfly_kc14/pom.xml
new file mode 100644
index 0000000..ba4ff50
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-servers</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-server-wildfly-kc14</artifactId>
+    <packaging>pom</packaging>
+    <name>Keycloak 1.4.0.Final on Wildfly</name>
+    
+    <properties>
+        <keycloak.server.home>${project.build.directory}/unpacked/keycloak-1.4.0.Final</keycloak.server.home>
+        <jdbc.mvn.driver.deployment.dir>${keycloak.server.home}/modules/system/layers/base/com/${jdbc.mvn.artifactId}/main</jdbc.mvn.driver.deployment.dir>
+    </properties>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>1.4</version>
+                <executions>
+                    <execution>
+                        <id>enforce-properties</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireProperty>
+                                    <property>jdbc.mvn.groupId</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>jdbc.mvn.artifactId</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>jdbc.mvn.version</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.url</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.user</property>
+                                </requireProperty>
+                                <requireProperty>
+                                    <property>keycloak.connectionsJpa.password</property>
+                                </requireProperty>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack-server</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-server-dist</artifactId>
+                                    <version>1.4.0.Final</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>jdbc-driver</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>${jdbc.mvn.groupId}</groupId>
+                                    <artifactId>${jdbc.mvn.artifactId}</artifactId>
+                                    <version>${jdbc.mvn.version}</version>
+                                    <type>jar</type>
+                                </artifactItem>
+                            </artifactItems>
+                            <outputDirectory>${jdbc.mvn.driver.deployment.dir}</outputDirectory>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>xml-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>configure-wildfly-datasource</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>transform</goal>
+                        </goals>
+                        <configuration>
+                            <transformationSets>
+                                <!-- create module.xml in modules -->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/modules/system/layers/base/com/h2database/h2/main</dir>
+                                    <stylesheet>src/main/xslt/module.xsl</stylesheet>
+                                    <includes>
+                                        <include>module.xml</include>
+                                    </includes>
+                                    <outputDir>${jdbc.mvn.driver.deployment.dir}</outputDir>
+                                    <parameters>
+                                        <parameter>
+                                            <name>database</name>
+                                            <value>${jdbc.mvn.artifactId}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>version</name>
+                                            <value>${jdbc.mvn.version}</value>
+                                        </parameter>
+                                    </parameters>
+                                </transformationSet>
+                                <!-- add datasource to standalone.xml -->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                    <stylesheet>src/main/xslt/datasource.xsl</stylesheet>
+                                    <includes>
+                                        <include>standalone.xml</include>
+                                    </includes>
+                                    <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                    <parameters>
+                                        <parameter>
+                                            <name>jdbc.url</name>
+                                            <value>${keycloak.connectionsJpa.url}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>driver</name>
+                                            <value>${jdbc.mvn.artifactId}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>username</name>
+                                            <value>${keycloak.connectionsJpa.user}</value>
+                                        </parameter>
+                                        <parameter>
+                                            <name>password</name>
+                                            <value>${keycloak.connectionsJpa.password}</value>
+                                        </parameter>
+                                    </parameters>
+                                </transformationSet>
+                                <!-- add logger for org.hibernate.dialect.Dialect to standalone.xml-->
+                                <transformationSet>
+                                    <dir>${keycloak.server.home}/standalone/configuration</dir>
+                                    <stylesheet>src/main/xslt/add-dialect-logger.xsl</stylesheet>
+                                    <includes>
+                                        <include>standalone.xml</include>
+                                    </includes>
+                                    <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+                                </transformationSet>
+                            </transformationSets>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>create-zip</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>assembly.xml</descriptor>
+                            </descriptors>
+                            <appendAssemblyId>false</appendAssemblyId>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/add-dialect-logger.xsl b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/add-dialect-logger.xsl
new file mode 100644
index 0000000..b5dc8c4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/add-dialect-logger.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+                xmlns:xalan="http://xml.apache.org/xalan" 
+                version="2.0"
+                exclude-result-prefixes="xalan">
+    
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:logging:'"/>
+
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+                        /*[local-name()='root-logger' and starts-with(namespace-uri(), $nsDS)]">
+        <logger category="org.hibernate.dialect.Dialect">
+            <level name="ALL"/>
+        </logger>
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+
+    <!-- Copy everything else. -->
+    <xsl:template match="@* | node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()"/>
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:3.0"
+                xmlns:ds="urn:jboss:domain:datasources:3.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+
+    <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+    
+    <!-- Remove keycloak datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+                         /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+    </xsl:template>
+    
+    <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+    <xsl:param name="driver" select="'h2'"/>
+    
+    <xsl:param name="username" select="'sa'"/>
+    <xsl:param name="password" select="'sa'"/>
+    
+    <xsl:param name="min.poolsize" select="'10'"/>
+    <xsl:param name="max.poolsize" select="'50'"/>
+    <xsl:param name="pool.prefill" select="'true'"/>
+    
+    <xsl:variable name="newDatasourceDefinition">
+        <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+            <connection-url>
+                <xsl:value-of select="$jdbc.url"/>
+            </connection-url>
+            <driver>
+                <xsl:value-of select="$driver"/>
+            </driver>
+            <security>
+                <user-name>
+                    <xsl:value-of select="$username"/>
+                </user-name>
+                <password>
+                    <xsl:value-of select="$password"/>
+                </password>
+            </security>
+            <pool>
+                <min-pool-size>
+                    <xsl:value-of select="$min.poolsize"/>
+                </min-pool-size>
+                <max-pool-size>
+                    <xsl:value-of select="$max.poolsize"/>
+                </max-pool-size>
+                <prefill>
+                    <xsl:value-of select="$pool.prefill"/>
+                </prefill>
+            </pool>
+        </datasource>
+    </xsl:variable>
+    
+    <xsl:variable name="newDriverDefinition">
+        <xsl:if test="$driver != 'h2'">
+            <driver name="{$driver}" module="com.{$driver}" />
+        </xsl:if>
+    </xsl:variable>
+    
+    <!-- Add new datasource definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDatasourceDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Add new driver definition. -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+		         /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+        <xsl:copy>
+            <xsl:copy-of select="$newDriverDefinition"/>
+            <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+    <!-- Copy everything else. -->
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:m="urn:jboss:module:1.3"
+                version="2.0"
+                exclude-result-prefixes="xalan m">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+    
+       
+    <xsl:param name="database" select="''"/>
+    <xsl:param name="version" select="''"/>
+    
+    <xsl:variable name="newModuleDefinition">
+        <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+            <resources>
+                <resource-root path="{$database}-{$version}.jar"/>
+            </resources>
+            <dependencies>
+                <module name="javax.api"/>
+                <module name="javax.transaction.api"/>
+            </dependencies>
+        </module>
+    </xsl:variable>
+    
+    <!-- clear whole document -->
+    <xsl:template match="/*" />
+    
+    <!-- Copy new module definition. -->
+    <xsl:template match="/*">
+        <xsl:copy-of select="$newModuleDefinition"/>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/pom.xml b/testsuite/integration-arquillian/tests/adapters/as7/pom.xml
new file mode 100644
index 0000000..701a6ef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/pom.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-tests-adapters</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-adapters-as7</artifactId>
+    <name>Adapter Tests on JBossAS 7</name>
+    
+    <properties>
+        <as7.version>7.1.1.Final</as7.version>
+        <app.server.as7.home>${containers.home}/jboss-as-${as7.version}</app.server.as7.home>
+        <adapter.libs.as7>${containers.home}/keycloak-as7-adapter-dist</adapter.libs.as7>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.as</groupId>
+            <artifactId>jboss-as-dist</artifactId>
+            <version>${as7.version}</version>
+            <type>zip</type>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-as7-adapter-dist</artifactId>
+            <type>zip</type>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.as</groupId>
+            <artifactId>jboss-as-arquillian-container-managed</artifactId>
+            <version>7.2.0.Final</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>  
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack-as7-and-adapter</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.jboss.as</groupId>
+                                    <artifactId>jboss-as-dist</artifactId>
+                                    <version>${as7.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${containers.home}</outputDirectory>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-as7-adapter-dist</artifactId>
+                                    <type>zip</type>
+                                    <outputDirectory>${adapter.libs.as7}</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <systemPropertyVariables>
+                        <app.server.as7>true</app.server.as7>
+                        <app.server.as7.home>${app.server.as7.home}</app.server.as7.home>
+                        <adapter.libs.as7>${adapter.libs.as7}</adapter.libs.as7>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    
+    
+    <profiles>
+        <profile>
+            <id>adapter-libs-provided</id>
+            <activation>    
+                <property>
+                    <name>!adapter.libs.bundled</name>
+                </property>
+            </activation>
+            <properties>
+                <adapter.libs.as7>${app.server.as7.home}</adapter.libs.as7>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>configure-adapter-subsystem</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>transform</goal>
+                                </goals>
+                                <configuration>
+                                    <transformationSets>
+                                        <transformationSet>
+                                            <dir>${app.server.as7.home}/standalone/configuration</dir>
+                                            <includes>
+                                                <include>standalone.xml</include>
+                                            </includes>
+                                            <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+                                            <outputDir>${app.server.as7.home}/standalone/configuration</outputDir>
+                                        </transformationSet>
+                                    </transformationSets>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>        
+    
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..8970850
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/arquillian.xsl
@@ -0,0 +1,36 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:a="http://jboss.org/schema/arquillian"
+                version="2.0"
+                exclude-result-prefixes="xalan a">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="/a:arquillian">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            
+            <container qualifier="app-server-as7" mode="manual" >
+                <configuration>
+                    <property name="enabled">${app.server.as7}</property>
+                    <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+                    <property name="jbossHome">${app.server.as7.home}</property>
+                    <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${app.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+                    <property name="managementAddress">localhost</property>
+                    <property name="managementPort">${app.server.management.port.jmx}</property>
+                </configuration>
+            </container>
+
+        </xsl:copy>
+    </xsl:template>
+    
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..5aac0f0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:1.2"
+                xmlns:ds="urn:jboss:domain:datasources:1.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.1"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:param name="config"/>
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="//j:extensions">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//j:profile">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//sec:security-domains">
+        <xsl:copy>
+            <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+            <security-domain name="keycloak">
+                <authentication>
+                    <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+            <security-domain name="sp" cache-type="default">
+                <authentication>
+                    <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7DemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7DemoServletsAdapterTest.java
new file mode 100644
index 0000000..f0258b2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7DemoServletsAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-as7")
+public class AS7DemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7SessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7SessionServletAdapterTest.java
new file mode 100644
index 0000000..9362ecd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7SessionServletAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-as7")
+public class AS7SessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/karaf/pom.xml b/testsuite/integration-arquillian/tests/adapters/karaf/pom.xml
new file mode 100644
index 0000000..06328fc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/karaf/pom.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-tests-adapters</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-adapters-karaf</artifactId>
+    <name>Adapter Tests on Karaf</name>
+    
+    <properties>
+        <karaf.version>3.0.3</karaf.version>
+        <karaf.home>${project.build.directory}/assembly</karaf.home>
+                
+        <!--fuse examples expect auth server on 8080-->
+        <auth.server.port.offset>0</auth.server.port.offset>
+        <auth.server.http.port>8080</auth.server.http.port>
+        <auth.server.management.port>9990</auth.server.management.port>
+        <!--fuse examples expect default karaf http port 8181-->
+        <app.server.http.port>8181</app.server.http.port>
+                
+    </properties>
+
+    <dependencies>
+        <!-- for karaf-maven-plugin -->
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>framework</artifactId>
+            <version>${karaf.version}</version>
+            <type>kar</type>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.karaf</groupId>
+            <artifactId>apache-camel</artifactId>
+            <version>2.12.5</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.karaf</groupId>
+            <artifactId>apache-cxf</artifactId>
+            <version>2.7.14</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-osgi-features</artifactId>
+            <version>${project.version}</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak.example.demo</groupId>
+            <artifactId>keycloak-fuse-example-features</artifactId>
+            <version>${project.version}</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <!-- for arquillian -->
+        <dependency>
+            <groupId>org.jboss.arquillian.container</groupId>
+            <artifactId>arquillian-container-karaf-managed</artifactId>
+            <version>2.1.0.CR18</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.jmx</groupId>
+            <artifactId>org.apache.aries.jmx</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+    </dependencies>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-maven-plugin</artifactId>
+                <version>${karaf.version}</version>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>prepare-karaf-with-examples</id>
+                        <phase>generate-test-resources</phase>
+                        <goals>
+                            <!-- creates custom karaf distro in ${project.build.directory}/assembly -->
+                            <goal>install-kars</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <bootFeatures>
+                        <!-- this installs all fuse examples -->
+                        <feature>keycloak-fuse-example</feature>
+                    </bootFeatures>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <systemPropertyVariables>
+                        <app.server.karaf>true</app.server.karaf>
+                        <karaf.home>${karaf.home}</karaf.home>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>xml-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/karaf/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/karaf/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..fabd47b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/karaf/src/main/xslt/arquillian.xsl
@@ -0,0 +1,38 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:a="http://jboss.org/schema/arquillian"
+                version="2.0"
+                exclude-result-prefixes="xalan a">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="/a:arquillian">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            
+            <container qualifier="app-server-karaf" mode="manual" >
+                <configuration>
+                    <property name="enabled">${app.server.karaf}</property>
+                    <property name="adapterImplClass">org.jboss.arquillian.container.osgi.karaf.managed.KarafManagedDeployableContainer</property>
+                    <property name="autostartBundle">false</property>
+                    <property name="karafHome">${karaf.home}</property>
+                    <property name="javaVmArguments">-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n ${adapter.test.props}</property>
+                    <property name="jmxServiceURL">service:jmx:rmi://127.0.0.1:44444/jndi/rmi://127.0.0.1:1099/karaf-root</property>
+                    <property name="jmxUsername">karaf</property>
+                    <property name="jmxPassword">karaf</property>            
+                </configuration>
+            </container>
+    
+        </xsl:copy>
+    </xsl:template>
+    
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/karaf/src/test/java/org/keycloak/testsuite/adapter/example/KarafFuseExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/karaf/src/test/java/org/keycloak/testsuite/adapter/example/KarafFuseExampleAdapterTest.java
new file mode 100644
index 0000000..eaf5f19
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/karaf/src/test/java/org/keycloak/testsuite/adapter/example/KarafFuseExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-karaf")
+public class KarafFuseExampleAdapterTest extends AbstractFuseExampleAdapterTest {
+    
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/pom.xml b/testsuite/integration-arquillian/tests/adapters/pom.xml
new file mode 100644
index 0000000..bcdf397
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/pom.xml
@@ -0,0 +1,348 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-tests</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-tests-adapters</artifactId>
+    <packaging>pom</packaging>
+    <name>Adapter Tests</name>
+    
+    <properties>
+        <app.server.port.offset>200</app.server.port.offset>
+        <app.server.http.port>8280</app.server.http.port>
+        <app.server.management.port>10190</app.server.management.port>
+        <app.server.management.port.jmx>10199</app.server.management.port.jmx>
+        <adapter.test.props>-Dapp.server.base.url=http://localhost:${app.server.http.port} -Dmy.host.name=localhost</adapter.test.props>
+        <exclude.adapters>-</exclude.adapters>
+    </properties>
+    
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <executions>
+                        <execution>
+                            <id>unpack-common-arquillian-xml</id>
+                            <phase>generate-resources</phase>
+                            <goals>
+                                <goal>unpack</goal>
+                            </goals>
+                            <configuration>
+                                <artifactItems>
+                                    <artifactItem>
+                                        <groupId>org.keycloak.testsuite</groupId>
+                                        <artifactId>integration-arquillian-tests-base</artifactId>
+                                        <version>${project.version}</version>
+                                        <type>test-jar</type>
+                                        <includes>**/arquillian.xml</includes>
+                                    </artifactItem>
+                                </artifactItems>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>            
+                <plugin>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>xml-maven-plugin</artifactId>
+                    <version>1.0</version>
+                    <executions>
+                        <execution>
+                            <id>add-app-server-to-arquillian-xml</id>
+                            <phase>process-resources</phase>
+                            <goals>
+                                <goal>transform</goal>
+                            </goals>
+                            <configuration>
+                                <transformationSets>
+                                    <transformationSet>
+                                        <dir>${project.build.directory}/dependency</dir>
+                                        <includes>
+                                            <include>arquillian.xml</include>
+                                        </includes>
+                                        <stylesheet>src/main/xslt/arquillian.xsl</stylesheet>
+                                        <outputDir>${project.build.directory}/dependency</outputDir>
+                                    </transformationSet>
+                                </transformationSets>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <configuration>
+                        <systemPropertyVariables>
+                            <arquillian.xml>${project.build.directory}/dependency/arquillian.xml</arquillian.xml>
+
+                            <app.server.port.offset>${app.server.port.offset}</app.server.port.offset>
+                            <app.server.http.port>${app.server.http.port}</app.server.http.port>
+                            <app.server.management.port>${app.server.management.port}</app.server.management.port>
+                            <app.server.management.port.jmx>${app.server.management.port.jmx}</app.server.management.port.jmx>
+                            
+                            <adapter.test.props>${adapter.test.props}</adapter.test.props>
+
+                            <adapter.libs.mode>bundled</adapter.libs.mode>
+                            <adapter.config.mode>provided</adapter.config.mode>
+                            
+                        </systemPropertyVariables>
+                        <excludes>
+                            <exclude>${exclude.adapters}</exclude>
+                        </excludes>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>        
+    </build>
+    
+    <profiles>
+
+        <profile>
+            <id>common-for-adapter-tests</id>
+            <activation>
+                <file>
+                    <exists>src</exists>
+                </file>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.keycloak.testsuite</groupId>
+                    <artifactId>integration-arquillian-tests-base</artifactId>
+                    <version>${project.version}</version>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak.testsuite</groupId>
+                    <artifactId>integration-arquillian-tests-base</artifactId>
+                    <version>${project.version}</version>
+                    <type>test-jar</type>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        
+        <profile>
+            <id>adapter-libs-provided</id>
+            <activation>    
+                <property>
+                    <name>!adapter.libs.bundled</name>
+                </property>
+            </activation>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <adapter.libs.mode>provided</adapter.libs.mode>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+        
+        <profile>
+            <id>examples</id>
+            <activation>
+                <property>
+                    <name>!skipTests</name>
+                </property>
+            </activation>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-dependency-plugin</artifactId>
+                            <version>2.10</version>
+                            <executions>
+                                <execution>
+                                    <id>example-wars</id>
+                                    <phase>generate-test-resources</phase>
+                                    <goals>
+                                        <goal>copy</goal>
+                                    </goals>
+                                    <configuration>
+                                        <artifactItems>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.example.demo</groupId>
+                                                <artifactId>product-portal-example</artifactId>        
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.example.demo</groupId>
+                                                <artifactId>customer-portal-example</artifactId>        
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>                                        
+                                            <artifactItem>
+                                                <groupId>org.keycloak.example.demo</groupId>
+                                                <artifactId>database-service</artifactId>        
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>       
+                                            <artifactItem>
+                                                <groupId>org.keycloak.example.demo</groupId>
+                                                <artifactId>js-console</artifactId>        
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                            <artifactItem>
+                                                <groupId>org.keycloak</groupId>
+                                                <artifactId>examples-multitenant</artifactId>        
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>                    
+                                            <artifactItem>
+                                                <groupId>org.keycloak</groupId>
+                                                <artifactId>examples-basicauth</artifactId>        
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.example.demo</groupId>
+                                                <artifactId>cors-angular-product-example</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.example.demo</groupId>
+                                                <artifactId>cors-database-service</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                        </artifactItems>
+                                        <outputDirectory>${examples.home}</outputDirectory>
+                                        <overWriteIfNewer>true</overWriteIfNewer>
+                                    </configuration>
+                                </execution>                            
+                                <execution>
+                                    <id>example-realms</id>
+                                    <phase>generate-test-resources</phase>
+                                    <goals>
+                                        <goal>unpack</goal>
+                                    </goals>
+                                    <configuration>
+                                        <artifactItems>
+                                            <artifactItem>
+                                                <groupId>org.keycloak</groupId>
+                                                <artifactId>keycloak-examples-dist</artifactId>        
+                                                <version>${project.version}</version>
+                                                <type>zip</type>
+                                                <includes>**/*realm.json</includes>
+                                            </artifactItem>
+                                        </artifactItems>
+                                        <outputDirectory>${examples.home}</outputDirectory>
+                                        <overWriteIfNewer>true</overWriteIfNewer>
+                                    </configuration>
+                                </execution>                            
+                            </executions>
+                        </plugin>            
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <examples.home>${examples.home}</examples.home>
+                                    <examples.version.suffix>${project.version}</examples.version.suffix>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                        <plugin>
+                            <artifactId>maven-resources-plugin</artifactId>
+                            <executions>
+                                <execution>
+                                    <id>copy-resources</id>
+                                    <phase>validate</phase>
+                                    <goals>
+                                        <goal>copy-resources</goal>
+                                    </goals>
+                                    <configuration>
+                                        <outputDirectory>${examples.home}</outputDirectory>
+                                        <resources>
+                                            <resource>
+                                                <directory>${basedir}/src/test/resources</directory>
+                                                <filtering>true</filtering>
+                                            </resource>
+                                        </resources>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+        
+        <profile>
+            <id>auth-server-wildfly</id>
+            <modules>
+                <module>wildfly-relative</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>app-server-wildfly</id>
+            <modules>
+                <module>wildfly</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>app-server-wildfly8</id>
+            <modules>
+                <module>wildfly8</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>app-server-as7</id>
+            <modules>
+                <module>as7</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>app-server-tomcat</id>
+            <modules>
+                <module>tomcat</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>app-server-karaf</id>
+            <modules>
+                <module>karaf</module>
+            </modules>
+        </profile>
+        <profile>
+            <id>no-adapter-tests</id>
+            <properties>
+                <!-- Exclude all adapters tests. -->
+                <exclude.adapters>**/adapter/**/*Test.java</exclude.adapters>
+            </properties>
+        </profile>
+        
+    </profiles>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/pom.xml b/testsuite/integration-arquillian/tests/adapters/tomcat/pom.xml
new file mode 100644
index 0000000..3d29d9f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/pom.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-tests-adapters</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-adapters-tomcat</artifactId>
+    <name>Adapter Tests on Tomcat</name>
+    
+    <properties>
+        <tomcat.version>8.0.23</tomcat.version>
+        <tomcat.home>${containers.home}/apache-tomcat-${tomcat.version}</tomcat.home>
+        <!-- FIXME disabled port-offset because tomcat doesn't support it -->
+        <app.server.port.offset>0</app.server.port.offset>
+        <app.server.http.port>8080</app.server.http.port>
+        <app.server.management.port>9990</app.server.management.port>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.arquillian.container</groupId>
+            <artifactId>arquillian-tomcat-managed-7</artifactId>
+            <version>1.0.0.CR7</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>2.10</version>
+                <executions>
+                    <execution>
+                        <id>unpack-tomcat-and-adapter</id>
+                        <phase>generate-test-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.apache.tomcat</groupId>
+                                    <artifactId>tomcat</artifactId>
+                                    <version>${tomcat.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${containers.home}</outputDirectory>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-tomcat8-adapter-dist</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${tomcat.home}/lib</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>libs-for-tomcat</id>
+                        <phase>generate-test-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.jboss.resteasy</groupId>
+                                    <artifactId>resteasy-client</artifactId>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.jboss.resteasy</groupId>
+                                    <artifactId>jaxrs-api</artifactId>
+                                </artifactItem>                                        
+                                <artifactItem>
+                                    <groupId>org.jboss.resteasy</groupId>
+                                    <artifactId>resteasy-jaxrs</artifactId>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>commons-io</groupId>
+                                    <artifactId>commons-io</artifactId>
+                                    <version>1.4</version>
+                                </artifactItem>
+                            </artifactItems>
+                            <outputDirectory>${tomcat.home}/lib</outputDirectory>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>xml-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>add-tomcat-manager-user</id>
+                        <phase>process-test-resources</phase>
+                        <goals>
+                            <goal>transform</goal>
+                        </goals>
+                        <configuration>
+                            <transformationSets>
+                                <transformationSet>
+                                    <dir>${tomcat.home}/conf</dir>
+                                    <stylesheet>src/main/xslt/tomcat-users.xsl</stylesheet>
+                                    <includes>
+                                        <include>tomcat-users.xml</include>
+                                    </includes>
+                                    <outputDir>${tomcat.home}/conf</outputDir>
+                                </transformationSet>
+                            </transformationSets>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <systemPropertyVariables>
+                        <app.server.tomcat>true</app.server.tomcat>
+                        <tomcat.home>${tomcat.home}</tomcat.home>
+                        <!-- TODO: implement port-offset for tomcat server.xml so we can shift from 8080 -->
+                        <app.server.management.port.tomcat>8089</app.server.management.port.tomcat>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..cd61687
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/arquillian.xsl
@@ -0,0 +1,39 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:a="http://jboss.org/schema/arquillian"
+                version="2.0"
+                exclude-result-prefixes="xalan a">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="/a:arquillian">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            
+            <container qualifier="app-server-tomcat" mode="manual" >
+                <configuration>
+                    <property name="enabled">${app.server.tomcat}</property>
+                    <property name="adapterImplClass">org.jboss.arquillian.container.tomcat.managed_7.TomcatManagedContainer</property>
+                    <property name="catalinaHome">${tomcat.home}</property>
+                    <property name="catalinaBase">${tomcat.home}</property>
+                    <property name="bindHttpPort">${app.server.http.port}</property>
+                    <property name="jmxPort">${app.server.management.port.tomcat}</property>
+                    <property name="user">manager</property>
+                    <property name="pass">arquillian</property>
+                    <property name="javaVmArguments">${adapter.test.props}</property>
+                </configuration>
+            </container>
+    
+        </xsl:copy>
+    </xsl:template>
+    
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/tomcat-users.xsl b/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/tomcat-users.xsl
new file mode 100644
index 0000000..59b61b3
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/tomcat-users.xsl
@@ -0,0 +1,23 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:tu="http://tomcat.apache.org/xml"
+                version="2.0"
+                exclude-result-prefixes="xalan tu">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no" />
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="//tu:tomcat-users">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <user username="manager" password="arquillian" roles="manager-script"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatBasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..95cfac0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatBasicAuthExampleAdapterTest.java
@@ -0,0 +1,15 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.junit.Ignore;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat")
+@Ignore
+public class TomcatBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
+
+    // TODO find out how to add context.xml dependent on app context (web.xml/module-name)
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatDemoExampleAdapterTest.java
new file mode 100644
index 0000000..99b219d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatDemoExampleAdapterTest.java
@@ -0,0 +1,16 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.junit.Ignore;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat")
+@Ignore
+public class TomcatDemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
+
+    // TODO find out how to add context.xml dependent on app context (web.xml/module-name)
+    
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatDemoServletsAdapterTest.java
new file mode 100644
index 0000000..822a4db
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatDemoServletsAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat")
+public class TomcatDemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatSessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatSessionServletAdapterTest.java
new file mode 100644
index 0000000..7dae041
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatSessionServletAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat")
+public class TomcatSessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/pom.xml b/testsuite/integration-arquillian/tests/adapters/wildfly/pom.xml
new file mode 100644
index 0000000..776ae8a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/pom.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-tests-adapters</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-adapters-wildfly</artifactId>
+    <name>Adapter Tests on Wildfly</name>
+    
+    <properties>
+        <app.server.wildfly.home>${containers.home}/wildfly-${wildfly.version}</app.server.wildfly.home>
+        <adapter.libs.wildfly>${containers.home}/keycloak-wf9-adapter-dist</adapter.libs.wildfly>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.wildfly</groupId>
+            <artifactId>wildfly-dist</artifactId>
+            <type>zip</type>
+        </dependency>
+        <dependency>
+            <groupId>org.wildfly</groupId>
+            <artifactId>wildfly-arquillian-container-managed</artifactId>
+        </dependency>                
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-wf9-adapter-dist</artifactId>
+            <type>zip</type>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>            
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack-wildfly-and-adapter</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.wildfly</groupId>
+                                    <artifactId>wildfly-dist</artifactId>
+                                    <version>${wildfly.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${containers.home}</outputDirectory>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-wf9-adapter-dist</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${adapter.libs.wildfly}</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.18.1</version>
+                <configuration>
+                    <systemPropertyVariables>
+                        <app.server.wildfly>true</app.server.wildfly>
+                        <app.server.wildfly.home>${app.server.wildfly.home}</app.server.wildfly.home>
+                        <adapter.libs.wildfly>${adapter.libs.wildfly}</adapter.libs.wildfly>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <profiles>
+        <profile>
+            <id>adapter-libs-provided</id>
+            <activation>    
+                <property>
+                    <name>!adapter.libs.bundled</name>
+                </property>
+            </activation>
+            <properties>
+                <adapter.libs.wildfly>${app.server.wildfly.home}</adapter.libs.wildfly>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>configure-adapter-subsystem</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>transform</goal>
+                                </goals>
+                                <configuration>
+                                    <transformationSets>
+                                        <transformationSet>
+                                            <dir>${app.server.wildfly.home}/standalone/configuration</dir>
+                                            <includes>
+                                                <include>standalone.xml</include>
+                                            </includes>
+                                            <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+                                            <outputDir>${app.server.wildfly.home}/standalone/configuration</outputDir>
+                                        </transformationSet>
+                                    </transformationSets>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>    
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..32017cb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/arquillian.xsl
@@ -0,0 +1,35 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:a="http://jboss.org/schema/arquillian"
+                version="2.0"
+                exclude-result-prefixes="xalan a">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="/a:arquillian">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            
+            <container qualifier="app-server-wildfly" mode="manual" >
+                <configuration>
+                    <property name="enabled">${app.server.wildfly}</property>
+                    <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+                    <property name="jbossHome">${app.server.wildfly.home}</property>
+                    <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${app.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+                    <property name="managementPort">${app.server.management.port}</property>
+                </configuration>
+            </container>
+            
+        </xsl:copy>
+    </xsl:template>
+    
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..a483717
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:3.0"
+                xmlns:ds="urn:jboss:domain:datasources:3.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:param name="config"/>
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="//j:extensions">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//j:profile">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//sec:security-domains">
+        <xsl:copy>
+            <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+            <security-domain name="keycloak">
+                <authentication>
+                    <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+            <security-domain name="sp" cache-type="default">
+                <authentication>
+                    <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..e16c864
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyDemoServletsAdapterTest.java
new file mode 100644
index 0000000..eaa24fc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyDemoServletsAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyDemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflySessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflySessionServletAdapterTest.java
new file mode 100644
index 0000000..0b2b489
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflySessionServletAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflySessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/pom.xml b/testsuite/integration-arquillian/tests/adapters/wildfly8/pom.xml
new file mode 100644
index 0000000..7c0a0dd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/pom.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-tests-adapters</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-adapters-wildfly8</artifactId>
+    <name>Adapter Tests on Wildfly 8</name>
+    
+    <properties>
+        <wildfly.version>8.2.1.Final</wildfly.version>
+        
+        <app.server.wildfly.home>${containers.home}/wildfly-${wildfly.version}</app.server.wildfly.home>
+        <adapter.libs.wildfly>${containers.home}/keycloak-wf8-adapter-dist</adapter.libs.wildfly>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.wildfly</groupId>
+            <artifactId>wildfly-dist</artifactId>
+            <type>zip</type>
+        </dependency>
+        <dependency>
+            <groupId>org.wildfly</groupId>
+            <artifactId>wildfly-arquillian-container-managed</artifactId>
+        </dependency>                
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-wf8-adapter-dist</artifactId>
+            <type>zip</type>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>            
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack-wildfly-and-adapter</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.wildfly</groupId>
+                                    <artifactId>wildfly-dist</artifactId>
+                                    <version>${wildfly.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${containers.home}</outputDirectory>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-wf8-adapter-dist</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>zip</type>
+                                    <outputDirectory>${adapter.libs.wildfly}</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.18.1</version>
+                <configuration>
+                    <systemPropertyVariables>
+                        <app.server.wildfly>true</app.server.wildfly>
+                        <app.server.wildfly.home>${app.server.wildfly.home}</app.server.wildfly.home>
+                        <adapter.libs.wildfly>${adapter.libs.wildfly}</adapter.libs.wildfly>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <profiles>
+        <profile>
+            <id>adapter-libs-provided</id>
+            <activation>    
+                <property>
+                    <name>!adapter.libs.bundled</name>
+                </property>
+            </activation>
+            <properties>
+                <adapter.libs.wildfly>${app.server.wildfly.home}</adapter.libs.wildfly>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>configure-adapter-subsystem</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>transform</goal>
+                                </goals>
+                                <configuration>
+                                    <transformationSets>
+                                        <transformationSet>
+                                            <dir>${app.server.wildfly.home}/standalone/configuration</dir>
+                                            <includes>
+                                                <include>standalone.xml</include>
+                                            </includes>
+                                            <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+                                            <outputDir>${app.server.wildfly.home}/standalone/configuration</outputDir>
+                                        </transformationSet>
+                                    </transformationSets>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>    
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..32017cb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/arquillian.xsl
@@ -0,0 +1,35 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:a="http://jboss.org/schema/arquillian"
+                version="2.0"
+                exclude-result-prefixes="xalan a">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="/a:arquillian">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            
+            <container qualifier="app-server-wildfly" mode="manual" >
+                <configuration>
+                    <property name="enabled">${app.server.wildfly}</property>
+                    <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+                    <property name="jbossHome">${app.server.wildfly.home}</property>
+                    <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${app.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+                    <property name="managementPort">${app.server.management.port}</property>
+                </configuration>
+            </container>
+            
+        </xsl:copy>
+    </xsl:template>
+    
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+    
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..364d803
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:2.2"
+                xmlns:ds="urn:jboss:domain:datasources:2.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:param name="config"/>
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="//j:extensions">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//j:profile">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//sec:security-domains">
+        <xsl:copy>
+            <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+            <security-domain name="keycloak">
+                <authentication>
+                    <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+            <security-domain name="sp" cache-type="default">
+                <authentication>
+                    <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..e746dd0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Wildfly8BasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8DemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8DemoServletsAdapterTest.java
new file mode 100644
index 0000000..469c6ca
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8DemoServletsAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Wildfly8DemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8SessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8SessionServletAdapterTest.java
new file mode 100644
index 0000000..a342403
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8SessionServletAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Wildfly8SessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/pom.xml b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/pom.xml
new file mode 100644
index 0000000..7d3ef2d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/pom.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-tests-adapters</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-adapters-wildfly-relative</artifactId>
+    <name>Adapter Tests on Wildfly Relative</name>
+    
+    <properties>
+        
+        <adapter.libs.wildfly>${containers.home}/keycloak-wf9-adapter-dist</adapter.libs.wildfly>
+
+        <!--this is needed for adapter tests that load system properties in adapter config-->
+        <app.server.http.port>${auth.server.http.port}</app.server.http.port>
+        
+    </properties>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.wildfly</groupId>
+            <artifactId>wildfly-arquillian-container-managed</artifactId>
+        </dependency>                 
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-wf9-adapter-dist</artifactId>
+            <type>zip</type>
+        </dependency>
+    </dependencies>
+    
+    <profiles>
+        <profile>
+            <id>adapter-libs-bundled</id>
+            <activation>    
+                <property>
+                    <name>adapter.libs.bundled</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unpack-adapter</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.keycloak</groupId>
+                                            <artifactId>keycloak-wf9-adapter-dist</artifactId>
+                                            <version>${project.version}</version>
+                                            <type>zip</type>
+                                            <outputDirectory>${adapter.libs.wildfly}</outputDirectory>
+                                        </artifactItem>
+                                    </artifactItems>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <systemPropertyVariables>
+                                <adapter.libs.wildfly>${adapter.libs.wildfly}</adapter.libs.wildfly>
+                            </systemPropertyVariables>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..ce09796
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/arquillian.xsl
@@ -0,0 +1,16 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:a="http://jboss.org/schema/arquillian"
+                version="2.0"
+                exclude-result-prefixes="xalan a">
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..a483717
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xalan="http://xml.apache.org/xalan"
+                xmlns:j="urn:jboss:domain:3.0"
+                xmlns:ds="urn:jboss:domain:datasources:3.0"
+                xmlns:k="urn:jboss:domain:keycloak:1.1"
+                xmlns:sec="urn:jboss:domain:security:1.2"
+                version="2.0"
+                exclude-result-prefixes="xalan j ds k sec">
+
+    <xsl:param name="config"/>
+
+    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:template match="//j:extensions">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//j:profile">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+            <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="//sec:security-domains">
+        <xsl:copy>
+            <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+            <security-domain name="keycloak">
+                <authentication>
+                    <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+            <security-domain name="sp" cache-type="default">
+                <authentication>
+                    <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+                </authentication>
+            </security-domain>
+        </xsl:copy>
+    </xsl:template>
+
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeBasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..5f45ebe
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeBasicAuthExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeCorsExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeCorsExampleAdapterTest.java
new file mode 100644
index 0000000..42ad346
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeCorsExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author fkiss
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeCorsExampleAdapterTest extends AbstractCorsExampleAdapterTest {
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeDemoExampleAdapterTest.java
new file mode 100644
index 0000000..afae885
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeDemoExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeDemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeJSConsoleExampleAdapterTest.java
new file mode 100644
index 0000000..c0026d0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeJSConsoleExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeJSConsoleExampleAdapterTest extends AbstractJSConsoleExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeDemoServletsAdapterTest.java
new file mode 100644
index 0000000..b23cfc5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeDemoServletsAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeDemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeSessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeSessionServletAdapterTest.java
new file mode 100644
index 0000000..17a3ae5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeSessionServletAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeSessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/resources/web.xml b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/resources/web.xml
new file mode 100644
index 0000000..1b6dc5e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/resources/web.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>%CONTEXT_PATH%</module-name>
+
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml
new file mode 100644
index 0000000..4ee4118
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-tests</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-tests-base</artifactId>
+    <name>Base Test Suite</name>
+
+    <properties>
+        <exclude.console>-</exclude.console>
+        <exclude.account>-</exclude.account>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.2</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>${exclude.console}</exclude>
+                        <exclude>${exclude.account}</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <profiles>    
+        <profile>
+            <id>no-console</id>
+            <properties>
+                <!-- Exclude all admin console tests. -->
+                <exclude.console>**/console/**/*Test.java</exclude.console>           
+            </properties>
+        </profile>
+        <profile>
+            <id>no-account</id>
+            <properties>
+                <!-- Exclude all account management tests. -->
+                <exclude.account>**/account/**/*Test.java</exclude.account>
+            </properties>
+        </profile>
+        <profile>
+            <id>adapters-only</id>
+            <properties>
+                <exclude.console>**/console/**/*Test.java</exclude.console>           
+                <exclude.account>**/account/**/*Test.java</exclude.account>
+            </properties>
+        </profile>
+    </profiles>
+    
+</project>
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/AdapterLibsMode.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/AdapterLibsMode.java
new file mode 100644
index 0000000..148a8d2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/AdapterLibsMode.java
@@ -0,0 +1,30 @@
+package org.keycloak.testsuite.adapter;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public enum AdapterLibsMode {
+    
+    PROVIDED("provided"),
+    BUNDLED("bundled");
+
+    private final String type;
+
+    private AdapterLibsMode(String type) {
+        this.type = type;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public static AdapterLibsMode getByType(String type) {
+        for (AdapterLibsMode s : AdapterLibsMode.values()) {
+            if (s.getType().equals(type)) {
+                return s;
+            }
+        }
+        return null;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AngularCorsProductExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AngularCorsProductExample.java
new file mode 100644
index 0000000..3520a3e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AngularCorsProductExample.java
@@ -0,0 +1,77 @@
+package org.keycloak.testsuite.adapter.page;
+
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.openqa.selenium.WebElement;
+
+import java.net.URL;
+
+/**
+ * Created by fkiss.
+ */
+public class AngularCorsProductExample extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "cors-angular-product-example";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+    @FindByJQuery("button:contains('Reload')")
+    private WebElement reloadDataButton;
+
+    @FindByJQuery("button:contains('load Roles')")
+    private WebElement loadRolesButton;
+
+    @FindByJQuery("button:contains('Add Role')")
+    private WebElement addRoleButton;
+
+    @FindByJQuery("button:contains('Delete Role')")
+    private WebElement deleteRoleButton;
+
+    @FindByJQuery("button:contains('load available social providers')")
+    private WebElement loadAvailableSocialProvidersButton;
+
+    @FindByJQuery("button:contains('Load public realm info')")
+    private WebElement loadPublicRealmInfoButton;
+
+    @FindByJQuery("button:contains('Load version')")
+    private WebElement loadVersionButton;
+
+    public void reloadData() {
+        reloadDataButton.click();
+    }
+
+    public void loadRoles() {
+        loadRolesButton.click();
+    }
+
+    public void addRole() {
+        addRoleButton.click();
+    }
+
+    public void deleteRole() {
+        deleteRoleButton.click();
+    }
+
+    public void loadAvailableSocialProviders() {
+        loadAvailableSocialProvidersButton.click();
+    }
+
+    public void loadPublicRealmInfo() {
+        loadPublicRealmInfoButton.click();
+    }
+
+    public void loadVersion() {
+        loadVersionButton.click();
+    }
+
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AppServerContextRoot.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AppServerContextRoot.java
new file mode 100644
index 0000000..0b68e05
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AppServerContextRoot.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.adapter.page;
+
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import java.net.URL;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContext;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AppServerContextRoot extends AbstractPageWithInjectedUrl {
+
+    @ArquillianResource
+    @AppServerContext
+    private URL appServerContextRoot;
+
+    @Override
+    public URL getInjectedUrl() {
+        return appServerContextRoot;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BasicAuthExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BasicAuthExample.java
new file mode 100644
index 0000000..f5cbcfb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BasicAuthExample.java
@@ -0,0 +1,41 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class BasicAuthExample extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "basic-auth-example";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder()
+                .userInfo("{user}:{password}")
+                .path("service/echo")
+                .queryParam("value", "{value}");
+    }
+
+    public BasicAuthExample setTemplateValues(String user, String password, String value) {
+        setUriParameter("user", user);
+        setUriParameter("password", password);
+        setUriParameter("value", value);
+        return this;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CorsDatabaseServiceExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CorsDatabaseServiceExample.java
new file mode 100644
index 0000000..4b72d6a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CorsDatabaseServiceExample.java
@@ -0,0 +1,26 @@
+package org.keycloak.testsuite.adapter.page;
+
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+import java.net.URL;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CorsDatabaseServiceExample extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "cors-database-service";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDb.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDb.java
new file mode 100644
index 0000000..0e9c387
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDb.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerDb extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "customer-db";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDbErrorPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDbErrorPage.java
new file mode 100644
index 0000000..82d72e1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDbErrorPage.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerDbErrorPage extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "customer-db-error-page";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortal.java
new file mode 100644
index 0000000..b3dcdf0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortal.java
@@ -0,0 +1,28 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerPortal extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "customer-portal";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortalExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortalExample.java
new file mode 100644
index 0000000..beaa8fa
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortalExample.java
@@ -0,0 +1,80 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerPortalExample extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "customer-portal-example";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+    @FindByJQuery("h1:contains('Customer Portal')")
+    private WebElement title;
+
+    @FindByJQuery("a:contains('Customer Listing')")
+    private WebElement customerListingLink;
+    @FindByJQuery("h1:contains('Customer Listing')")
+    private WebElement customerListingHeader;
+
+    @FindByJQuery("h1:contains('Customer Session')")
+    private WebElement customerSessionHeader;
+
+    @FindByJQuery("a:contains('Customer Admin Interface')")
+    private WebElement customerAdminInterfaceLink;
+
+    @FindByJQuery("a:contains('Customer Session')")
+    private WebElement customerSessionLink;
+
+    @FindByJQuery("a:contains('products')")
+    private WebElement productsLink;
+
+    @FindByJQuery("a:contains('logout')")
+    private WebElement logOutButton;
+
+    public void goToProducts() {
+        productsLink.click();
+    }
+
+    public void customerListing() {
+        customerListingLink.click();
+    }
+
+    public void customerAdminInterface() {
+        customerAdminInterfaceLink.click();
+    }
+
+    public void customerSession() {
+        WaitUtils.waitGuiForElement(customerSessionLink);
+        customerSessionLink.click();
+    }
+
+    public void logOut() {
+        logOutButton.click();
+    }
+
+    public void waitForCustomerListingHeader() {
+        WaitUtils.waitGuiForElementNotPresent(customerListingHeader);
+    }
+
+    public void waitForCustomerSessionHeader() {
+        WaitUtils.waitGuiForElementNotPresent(customerSessionHeader);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/DatabaseServiceExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/DatabaseServiceExample.java
new file mode 100644
index 0000000..1bbc4c7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/DatabaseServiceExample.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class DatabaseServiceExample extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "database-service-example";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AbstractFuseExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AbstractFuseExample.java
new file mode 100644
index 0000000..18e821a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AbstractFuseExample.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.keycloak.testsuite.adapter.page.AppServerContextRoot;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractFuseExample extends AppServerContextRoot {
+
+    public abstract String getContext();
+
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        if (url == null) {
+            try {
+                url = new URL(super.getInjectedUrl().toExternalForm() + "/" + getContext());
+            } catch (MalformedURLException ex) {
+                throw new IllegalStateException(ex);
+            }
+        }
+        return url;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AdminInterface.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AdminInterface.java
new file mode 100644
index 0000000..2921a5b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AdminInterface.java
@@ -0,0 +1,17 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminInterface extends CustomerPortalFuseExample {
+
+    @Override
+    public String getContext() {
+        return super.getContext() + "/customers/camel.jsp";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerListing.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerListing.java
new file mode 100644
index 0000000..01f3f3d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerListing.java
@@ -0,0 +1,36 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerListing extends CustomerPortalFuseExample {
+
+    @Override
+    public String getContext() {
+        return super.getContext() + "/customers/cxf-rs.jsp";
+    }
+
+    @FindBy(linkText = "products")
+    protected WebElement productsLink;
+    @FindBy(linkText = "logout")
+    protected WebElement logOutLink;
+    @FindBy(linkText = "manage acct")
+    protected WebElement accountManagementLink;
+
+    public void clickProducts() {
+        productsLink.click();
+    }
+
+    public void clickLogOut() {
+        logOutLink.click();
+    }
+
+    public void clickAccountManagement() {
+        accountManagementLink.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerPortalFuseExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerPortalFuseExample.java
new file mode 100644
index 0000000..6d1f656
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerPortalFuseExample.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerPortalFuseExample extends AbstractFuseExample {
+
+    public static final String DEPLOYMENT_NAME = "customer-portal-fuse-example";
+    public static final String DEPLOYMENT_CONTEXT = "customer-portal";
+
+    @Override
+    public String getContext() {
+        return DEPLOYMENT_CONTEXT;
+    }
+
+    @FindBy(linkText = "Customer Listing - CXF RS endpoint")
+    protected WebElement customerListingLink;
+
+    @FindBy(linkText = "Admin Interface - Apache Camel endpoint")
+    protected WebElement adminInterfaceLink;
+
+    public void clickCustomerListingLink() {
+        customerListingLink.click();
+    }
+
+    public void clickAdminInterfaceLink() {
+        adminInterfaceLink.click();
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/ProductPortalFuseExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/ProductPortalFuseExample.java
new file mode 100644
index 0000000..b61222e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/ProductPortalFuseExample.java
@@ -0,0 +1,50 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ProductPortalFuseExample extends AbstractFuseExample {
+
+    public static final String DEPLOYMENT_NAME = "product-portal-fuse-example";
+    public static final String DEPLOYMENT_CONTEXT = "product-portal";
+
+    @Override
+    public String getContext() {
+        return DEPLOYMENT_CONTEXT;
+    }
+
+    @FindBy(linkText = "products")
+    protected WebElement productsLink;
+    @FindBy(linkText = "logout")
+    protected WebElement logOutLink;
+    @FindBy(linkText = "manage acct")
+    protected WebElement accountManagementLink;
+
+    @FindBy(xpath = "//p[contains(text(),'Product with ID 1 - unsecured request')]")
+    protected WebElement product1Unsecured;
+    @FindBy(xpath = "//p[contains(text(),'Product with ID 1 - secured request')]")
+    protected WebElement product1Secured;
+    @FindBy(xpath = "//p[contains(text(),'Product with ID 2 - secured request')]")
+    protected WebElement product2Secured;
+
+    public String getProduct1UnsecuredText() {
+        return product1Unsecured.getText();
+    }
+
+    public String getProduct1SecuredText() {
+        return product1Secured.getText();
+    }
+
+    public String getProduct2SecuredText() {
+        return product2Secured.getText();
+    }
+
+    public void clickLogOutLink() {
+        logOutLink.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java
new file mode 100644
index 0000000..564272f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class InputPortal extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "input-portal";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+    @FindBy(id = "parameter")
+    private WebElement parameter;
+
+    @FindBy(name = "submit")
+    private WebElement submit;
+
+    public void execute(String param) {
+        parameter.clear();
+        parameter.sendKeys(param);
+        submit.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleExample.java
new file mode 100644
index 0000000..787be4d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleExample.java
@@ -0,0 +1,70 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class JSConsoleExample extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "js-console-example";
+    public static final String CLIENT_ID = "js-console";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+    @FindBy(xpath = "//button[text() = 'Login']")
+    private WebElement logInButton;
+    @FindBy(xpath = "//button[text() = 'Logout']")
+    private WebElement logOutButton;
+    @FindBy(xpath = "//button[text() = 'Refresh Token']")
+    private WebElement refreshTokenButton;
+    @FindBy(xpath = "//button[contains(text(),'Refresh Token (if <30s')]")
+    private WebElement refreshTokenIfUnder30sButton;
+    @FindBy(xpath = "//button[text() = 'Get Profile']")
+    private WebElement getProfileButton;
+
+    @FindBy(xpath = "//button[text() = 'Show Token']")
+    private WebElement showTokenButton;
+    @FindBy(xpath = "//button[text() = 'Show Refresh Token']")
+    private WebElement showRefreshTokenButton;
+    @FindBy(xpath = "//button[text() = 'Show ID Token']")
+    private WebElement showIdTokenButton;
+    @FindBy(xpath = "//button[text() = 'Show Expires']")
+    private WebElement showExpiresButton;
+    @FindBy(xpath = "//button[text() = 'Show Details']")
+    private WebElement showDetailsButton;
+
+    public void logIn() {
+        logInButton.click();
+    }
+
+    public void logOut() {
+        logOutButton.click();
+    }
+
+    public void refreshToken() {
+        refreshTokenButton.click();
+    }
+
+    public void refreshTokenIfUnder30s() {
+        refreshTokenIfUnder30sButton.click();
+    }
+
+    public void getProfile() {
+        getProfileButton.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant.java
new file mode 100644
index 0000000..3cb7fb6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant.java
@@ -0,0 +1,46 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class MultiTenant extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "multi-tenant";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder().path("/").queryParam("realm", "{tenantRealm}");
+    }
+
+    public URL getTenantRealmUrl(String realm) {
+        try {
+            return getUriBuilder().build(realm).toURL();
+        } catch (MalformedURLException ex) {
+            throw new IllegalStateException("Page URL is malformed.");
+        }
+    }
+
+    public void navigateToRealm(String realm) {
+        URL u = getTenantRealmUrl(realm);
+        log.info("navigate to "+u.toExternalForm());
+        driver.navigate().to(u.toExternalForm());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenantExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenantExample.java
new file mode 100644
index 0000000..a8e582d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenantExample.java
@@ -0,0 +1,46 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class MultiTenantExample extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "multi-tenant-example";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder().path("{tenantRealm}");
+    }
+
+    public URL getTenantRealmUrl(String realm) {
+        try {
+            return getUriBuilder().build(realm).toURL();
+        } catch (MalformedURLException ex) {
+            throw new IllegalStateException("Page URL is malformed.");
+        }
+    }
+
+    public void navigateToRealm(String realm) {
+        URL u = getTenantRealmUrl(realm);
+        log.info("navigate to "+u.toExternalForm());
+        driver.navigate().to(u.toExternalForm());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortal.java
new file mode 100644
index 0000000..96cd1b1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortal.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ProductPortal extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "product-portal";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortalExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortalExample.java
new file mode 100644
index 0000000..fd80e5d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortalExample.java
@@ -0,0 +1,59 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ProductPortalExample extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "product-portal-example";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+    @FindByJQuery("h1:contains('Product Portal')")
+    private WebElement title;
+
+    @FindByJQuery("a:contains('Product Listing')")
+    private WebElement productListingLink;
+    @FindByJQuery("h1:contains('Product Listing')")
+    private WebElement productListingHeader;
+
+    @FindByJQuery("a:contains('customers')")
+    private WebElement customersLink;
+
+    @FindByJQuery("a:contains('logout')")
+    private WebElement logOutButton;
+
+    public void productListing() {
+        productListingLink.click();
+    }
+
+    public void goToCustomers() {
+        customersLink.click();
+    }
+
+    public void waitForProductListingHeader() {
+        WaitUtils.waitGuiForElementNotPresent(productListingHeader);
+    }
+
+    public void logOut() {
+        logOutButton.click();
+    }
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SecurePortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SecurePortal.java
new file mode 100644
index 0000000..4825fef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SecurePortal.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class SecurePortal extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "secure-portal";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SessionPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SessionPortal.java
new file mode 100644
index 0000000..0e597c6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SessionPortal.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class SessionPortal extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "session-portal";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CallAuthenticatedServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CallAuthenticatedServlet.java
new file mode 100644
index 0000000..b5f7f7c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CallAuthenticatedServlet.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.KeycloakSecurityContext;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CallAuthenticatedServlet extends HttpServlet {
+
+    private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        if (!req.authenticate(resp)) {
+            return;
+        }
+
+        KeycloakSecurityContext sc = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+        if (sc == null) { // assert sc not null
+            throw new AssertionError("Keycloak security context is null.");
+        }
+        resp.setContentType("text/html");
+        PrintWriter pw = resp.getWriter();
+        pw.printf("<html><head><title>%s</title></head><body>", "Customer Portal");
+        pw.println("Stian Thorgersen");
+        pw.println("Bill Burke");
+        pw.print("</body></html>");
+        pw.flush();
+
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerDatabaseServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerDatabaseServlet.java
new file mode 100644
index 0000000..0e581cd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerDatabaseServlet.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CustomerDatabaseServlet extends HttpServlet {
+    private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        resp.setContentType("text/html");
+        PrintWriter pw = resp.getWriter();
+        pw.printf("<html><head><title>%s</title></head><body>", "Customer Portal");
+        pw.println("Stian Thorgersen");
+        pw.println("Bill Burke");
+        pw.print("</body></html>");
+        pw.flush();
+
+
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerServlet.java
new file mode 100644
index 0000000..9d03c1f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerServlet.java
@@ -0,0 +1,59 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.KeycloakSecurityContext;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.annotation.WebServlet;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@WebServlet("/customer-portal")
+public class CustomerServlet extends HttpServlet {
+    private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        PrintWriter pw = resp.getWriter();
+        if (req.getRequestURI().endsWith("logout")) {
+            resp.setStatus(200);
+            pw.println("servlet logout ok");
+
+            // Call logout before pw.flush
+            req.logout();
+            pw.flush();
+            return;
+        }
+        KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
+        Client client = ClientBuilder.newClient();
+
+        try {
+            String appBase = System.getProperty("app.server.base.url", "http://localhost:8280");
+            WebTarget target = client.target(appBase + "/customer-db/");
+            Response response = target.request().get();
+            if (response.getStatus() != 401) { // assert response status == 401
+                throw new AssertionError("Response status code is not 401.");
+            }
+            response.close();
+            String html = target.request()
+                                .header(HttpHeaders.AUTHORIZATION, "Bearer " + context.getTokenString())
+                                .get(String.class);
+            resp.setContentType("text/html");
+            pw.println(html);
+            pw.flush();
+        } finally {
+            client.close();
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ErrorServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ErrorServlet.java
new file mode 100644
index 0000000..55cac40
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ErrorServlet.java
@@ -0,0 +1,27 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ErrorServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+
+        resp.setContentType("text/html");
+        PrintWriter pw = resp.getWriter();
+        pw.printf("<html><head><title>%s</title></head><body>", "Error Page");
+        pw.print("<h1>There was an error</h1></body></html>");
+        pw.flush();
+
+
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java
new file mode 100644
index 0000000..0834d95
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java
@@ -0,0 +1,43 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.annotation.WebServlet;
+
+/**
+ * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
+ */
+@WebServlet("/input-portal")
+public class InputServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String appBase = System.getProperty("app.server.base.url", "http://localhost:8280");
+        String actionUrl = appBase + "/input-portal/secured/post";
+
+
+        resp.setContentType("text/html");
+        PrintWriter pw = resp.getWriter();
+        pw.printf("<html><head><title>%s</title></head><body>", "Input Page");
+        pw.printf("<form action=\"%s\" method=\"POST\">", actionUrl);
+        pw.println("<input id=\"parameter\" type=\"text\" name=\"parameter\">");
+        pw.println("<input name=\"submit\" type=\"submit\" value=\"Submit\"></form>");
+        pw.print("</body></html>");
+        pw.flush();
+
+
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        resp.setContentType("text/plain");
+        PrintWriter pw = resp.getWriter();
+        pw.printf("parameter="+req.getParameter("parameter"));
+        pw.flush();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantResolver.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantResolver.java
new file mode 100644
index 0000000..765e291
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantResolver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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;
+
+import java.io.InputStream;
+import org.keycloak.adapters.HttpFacade;
+import org.keycloak.adapters.KeycloakConfigResolver;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.KeycloakDeploymentBuilder;
+
+/**
+ *
+ * @author Juraci Paixão Kröhling <juraci at kroehling.de>
+ */
+public class MultiTenantResolver implements KeycloakConfigResolver {
+
+    @Override
+    public KeycloakDeployment resolve(HttpFacade.Request request) {
+        String realm = request.getQueryParamValue("realm");
+
+        // FIXME doesn't work - need to load resources from WEB-INF
+        InputStream is = getClass().getResourceAsStream("/" + realm + "-keycloak.json");
+
+        if (is == null) {
+            throw new IllegalStateException("Not able to find the file /" + realm + "-keycloak.json");
+        }
+
+        KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(is);
+        return deployment;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantServlet.java
new file mode 100644
index 0000000..ccbf97a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantServlet.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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;
+
+import org.keycloak.KeycloakSecurityContext;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ *
+ * @author Juraci Paixão Kröhling <juraci at kroehling.de>
+ */
+public class MultiTenantServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        resp.setContentType("text/html");
+        PrintWriter pw = resp.getWriter();
+        KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
+
+        pw.print("Username: ");
+        pw.println(context.getIdToken().getPreferredUsername());
+
+        pw.print("<br/>Realm: ");
+        pw.println(context.getRealm());
+
+        pw.flush();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ProductServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ProductServlet.java
new file mode 100644
index 0000000..ce89986
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ProductServlet.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ProductServlet extends HttpServlet {
+    private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        resp.setContentType("text/html");
+        PrintWriter pw = resp.getWriter();
+        pw.printf("<html><head><title>%s</title></head><body>", "Product Portal");
+        pw.println("iPhone");
+        pw.println("iPad");
+        pw.print("</body></html>");
+        pw.flush();
+
+
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SessionServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SessionServlet.java
new file mode 100644
index 0000000..584408e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SessionServlet.java
@@ -0,0 +1,40 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@WebServlet("/SessionServlet")
+public class SessionServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String counter = increaseAndGetCounter(req);
+
+        resp.setContentType("text/html");
+        PrintWriter pw = resp.getWriter();
+        pw.printf("<html><head><title>%s</title></head><body>", "Session Test");
+        pw.printf("Counter=%s", counter);
+        pw.print("</body></html>");
+        pw.flush();
+
+
+    }
+
+    private String increaseAndGetCounter(HttpServletRequest req) {
+        HttpSession session = req.getSession();
+        Integer counter = (Integer)session.getAttribute("counter");
+        counter = (counter == null) ? 1 : counter + 1;
+        session.setAttribute("counter", counter);
+        return String.valueOf(counter);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
new file mode 100644
index 0000000..eb202e5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
@@ -0,0 +1,111 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.admin;
+
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.RoleScopeResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ * Created by st on 28.05.15.
+ */
+public class ApiUtil {
+
+    public static String getCreatedId(Response response) {
+        URI location = response.getLocation();
+        if (location == null) {
+            return null;
+        }
+        String path = location.getPath();
+        return path.substring(path.lastIndexOf('/') + 1);
+    }
+
+    public static ClientResource findClientResourceByClientId(RealmResource realm, String clientId) {
+        for (ClientRepresentation c : realm.clients().findAll()) {
+            if (c.getClientId().equals(clientId)) {
+                return realm.clients().get(c.getId());
+            }
+        }
+        return null;
+    }
+
+    public static ClientRepresentation findClientByClientId(RealmResource realm, String clientId) {
+        ClientRepresentation client = null;
+        for (ClientRepresentation c : realm.clients().findAll()) {
+            if (clientId.equals(c.getClientId())) {
+                client = c;
+            }
+        }
+        return client;
+    }
+
+    public static UserRepresentation findUserByUsername(RealmResource realm, String username) {
+        UserRepresentation user = null;
+        List<UserRepresentation> ur = realm.users().search(username, null, null);
+        if (ur.size() == 1) {
+            user = ur.get(0);
+        }
+        return user;
+    }
+
+    public static String createUserWithAdminClient(RealmResource realm, UserRepresentation user) {
+        Response response = realm.users().create(user);
+        String createdId = getCreatedId(response);
+        response.close();
+        return createdId;
+    }
+    
+    public static String createUserAndResetPasswordWithAdminClient(RealmResource realm, UserRepresentation user, String password) {
+        String id = createUserWithAdminClient(realm, user);
+        resetUserPassword(realm.users().get(id), password, false);
+        return id;
+    }
+
+    public static void resetUserPassword(UserResource userResource, String newPassword, boolean temporary) {
+        CredentialRepresentation newCredential = new CredentialRepresentation();
+        newCredential.setType(PASSWORD);
+        newCredential.setValue(newPassword);
+        newCredential.setTemporary(temporary);
+        userResource.resetPassword(newCredential);
+    }
+
+    public static void assignClientRoles(UserResource userResource, String clientId, String... roles) {
+        RoleScopeResource rsr = userResource.roles().clientLevel(clientId);
+        List<String> rolesList = Arrays.asList(roles);
+        List<RoleRepresentation> realmMgmtRoles = new ArrayList<>();
+        for (RoleRepresentation rr : rsr.listAvailable()) {
+            if (rolesList.contains(rr.getName())) {
+                realmMgmtRoles.add(rr);
+            }
+        }
+        rsr.add(realmMgmtRoles);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/Users.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/Users.java
new file mode 100644
index 0000000..c2a2f7a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/Users.java
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.admin;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class Users {
+
+    public static String getPasswordOf(UserRepresentation user) {
+        String value = null;
+        CredentialRepresentation password = getPasswordCredentialOf(user);
+        if (password != null) {
+            value = password.getValue();
+        }
+        return value;
+    }
+
+    public static CredentialRepresentation getPasswordCredentialOf(UserRepresentation user) {
+        CredentialRepresentation password = null;
+        if (user.getCredentials() != null) {
+            for (CredentialRepresentation c : user.getCredentials()) {
+                if (CredentialRepresentation.PASSWORD.equals(c.getType())) {
+                    password = c;
+                }
+            }
+        }
+        return password;
+    }
+
+    public static void setPasswordFor(UserRepresentation user, String password) {
+        setPasswordFor(user, password, false);
+    }
+    public static void setPasswordFor(UserRepresentation user, String password, boolean temporary) {
+        List<CredentialRepresentation> credentials = new ArrayList<>();
+        CredentialRepresentation pass = new CredentialRepresentation();
+        pass.setType(PASSWORD);
+        pass.setValue(password);
+        pass.setTemporary(temporary);
+        credentials.add(pass);
+        user.setCredentials(credentials);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AdapterLibsLocationProperty.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AdapterLibsLocationProperty.java
new file mode 100644
index 0000000..ec0fe1d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AdapterLibsLocationProperty.java
@@ -0,0 +1,19 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.TYPE})
+public @interface AdapterLibsLocationProperty 
+{
+   String value();
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java
new file mode 100644
index 0000000..b8169f8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java
@@ -0,0 +1,20 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.TYPE})
+public @interface AppServerContainer 
+{
+   String value() default "";
+   String adapterLibsLocationProperty() default "";
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContext.java
new file mode 100644
index 0000000..203ac65
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContext.java
@@ -0,0 +1,18 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.FIELD})
+public @interface AppServerContext 
+{
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AuthServerContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AuthServerContext.java
new file mode 100644
index 0000000..a35bbde
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AuthServerContext.java
@@ -0,0 +1,18 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.FIELD})
+public @interface AuthServerContext 
+{
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java
new file mode 100644
index 0000000..c4476ef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java
@@ -0,0 +1,61 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.arquillian.containers;
+
+import java.util.logging.Logger;
+
+import org.jboss.arquillian.container.impl.client.ContainerDeploymentContextHandler;
+import org.jboss.arquillian.container.impl.client.container.ContainerDeployController;
+import org.jboss.arquillian.container.impl.client.container.ContainerLifecycleController;
+import org.jboss.arquillian.container.impl.client.container.DeploymentExceptionHandler;
+import org.jboss.arquillian.container.impl.client.deployment.ArchiveDeploymentExporter;
+import org.jboss.arquillian.container.impl.context.ContainerContextImpl;
+import org.jboss.arquillian.container.impl.context.DeploymentContextImpl;
+import org.jboss.arquillian.core.spi.LoadableExtension;
+
+/**
+ * Enables multiple container adapters on classpath.
+ *
+ * @author Dominik Pospisil <dpospisi@redhat.com>
+ * @author Stefan Miklosovic <smikloso@redhat.com>
+ * @author Tomas Kyjovsky <tkyjovsk@redhat.com>
+ */
+public class MultipleContainersExtension implements LoadableExtension {
+
+    private static final Logger logger = Logger.getLogger(MultipleContainersExtension.class.getName());
+
+    @Override
+    public void register(ExtensionBuilder builder) {
+
+        logger.info("Multiple containers extension registering.");
+
+        builder.context(ContainerContextImpl.class).context(DeploymentContextImpl.class);
+
+        builder.observer(RegistryCreator.class)
+                .observer(ContainerDeploymentContextHandler.class)
+                .observer(ContainerLifecycleController.class)
+                .observer(ContainerDeployController.class)
+                .observer(ArchiveDeploymentExporter.class)
+                .observer(DeploymentExceptionHandler.class);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/Registry.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/Registry.java
new file mode 100644
index 0000000..2564b7a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/Registry.java
@@ -0,0 +1,148 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.arquillian.containers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.jboss.arquillian.config.descriptor.api.ContainerDef;
+import org.jboss.arquillian.container.impl.ContainerCreationException;
+import org.jboss.arquillian.container.impl.ContainerImpl;
+import org.jboss.arquillian.container.spi.ConfigurationException;
+import org.jboss.arquillian.container.spi.Container;
+import org.jboss.arquillian.container.spi.ContainerRegistry;
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.container.spi.client.deployment.TargetDescription;
+import org.jboss.arquillian.core.api.Injector;
+import org.jboss.arquillian.core.spi.ServiceLoader;
+import org.jboss.arquillian.core.spi.Validate;
+import static org.keycloak.testsuite.arquillian.containers.RegistryCreator.getAdapterImplClassValue;
+import static org.keycloak.testsuite.arquillian.containers.RegistryCreator.getContainerAdapter;
+
+/**
+ * This class registers all adapters which are specified in the arquillian.xml.
+ *
+ * In the case there is only one adapter implementation on the classpath, it is
+ * not necessary to specify it in the container configuration since it will be
+ * used automatically. You have to specify it only in the case you are going to
+ * use more than one container.
+ *
+ * @author Dominik Pospisil <dpospisi@redhat.com>
+ * @author Stefan Miklosovic <smikloso@redhat.com>
+ * @author Tomas Kyjovsky <tkyjovsk@redhat.com>
+ */
+public class Registry implements ContainerRegistry {
+
+    private final List<Container> containers;
+
+    private Injector injector;
+
+    private static final Logger logger = Logger.getLogger(RegistryCreator.class.getName());
+
+    public Registry(Injector injector) {
+        this.containers = new ArrayList<>();
+        this.injector = injector;
+    }
+
+    @Override
+    public Container create(ContainerDef definition, ServiceLoader loader) {
+        Validate.notNull(definition, "Definition must be specified");
+
+        try {
+            logger.log(Level.INFO, "Registering container: {0}", definition.getContainerName());
+
+            @SuppressWarnings("rawtypes")
+            Collection<DeployableContainer> containerAdapters = loader.all(DeployableContainer.class);
+
+            DeployableContainer<?> dcService = null;
+
+            if (containerAdapters.size() == 1) {
+                // just one container on cp
+                dcService = containerAdapters.iterator().next();
+            } else {
+                if (dcService == null) {
+                    dcService = getContainerAdapter(getAdapterImplClassValue(definition), containerAdapters);
+                }
+                if (dcService == null) {
+                    throw new ConfigurationException("Unable to get container adapter from Arquillian configuration.");
+                }
+            }
+
+            // before a Container is added to a collection of containers, inject into its injection point
+            return addContainer(injector.inject(
+                    new ContainerImpl(definition.getContainerName(), dcService, definition)));
+
+        } catch (Exception e) {
+            throw new ContainerCreationException("Could not create Container " + definition.getContainerName(), e);
+        }
+    }
+
+    @Override
+    public List<Container> getContainers() {
+        return Collections.unmodifiableList(new ArrayList<>(containers));
+    }
+
+    @Override
+    public Container getContainer(TargetDescription target) {
+        Validate.notNull(target, "Target must be specified");
+        if (TargetDescription.DEFAULT.equals(target)) {
+            return findDefaultContainer();
+        }
+        return findMatchingContainer(target.getName());
+    }
+
+    private Container addContainer(Container container) {
+        containers.add(container);
+        return container;
+    }
+
+    private Container findDefaultContainer() {
+        if (containers.size() == 1) {
+            return containers.get(0);
+        }
+        for (Container container : containers) {
+            if (container.getContainerConfiguration().isDefault()) {
+                return container;
+            }
+        }
+        return null;
+    }
+
+    private Container findMatchingContainer(String name) {
+        for (Container container : containers) {
+            if (container.getName().equals(name)) {
+                return container;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Container getContainer(String name) {
+        return findMatchingContainer(name);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/RegistryCreator.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/RegistryCreator.java
new file mode 100644
index 0000000..ffcccd5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/RegistryCreator.java
@@ -0,0 +1,186 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.arquillian.containers;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
+import org.jboss.arquillian.config.descriptor.api.ContainerDef;
+import org.jboss.arquillian.config.descriptor.api.GroupDef;
+import org.jboss.arquillian.container.spi.ContainerRegistry;
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.core.api.Injector;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.InstanceProducer;
+import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.core.api.annotation.Observes;
+import org.jboss.arquillian.core.spi.ServiceLoader;
+import org.jboss.arquillian.core.spi.Validate;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.arquillian.containers.SecurityActions.isClassPresent;
+import static org.keycloak.testsuite.arquillian.containers.SecurityActions.loadClass;
+
+/**
+ * Registers all container adapters.
+ *
+ * @author Dominik Pospisil <dpospisi@redhat.com>
+ * @author Stefan Miklosovic <smikloso@redhat.com>
+ * @author Tomas Kyjovsky <tkyjovsk@redhat.com>
+ * @author Vlasta Ramik <vramik@redhat.com>
+ */
+public class RegistryCreator {
+
+    protected final Logger log = Logger.getLogger(this.getClass());
+
+    @Inject
+    @ApplicationScoped
+    private InstanceProducer<ContainerRegistry> registry;
+
+    @Inject
+    private Instance<Injector> injector;
+
+    @Inject
+    private Instance<ServiceLoader> loader;
+    
+    private String authContainer;
+    private String migrationContainer;
+    
+    public void createRegistry(@Observes ArquillianDescriptor event) {
+        ContainerRegistry reg = new Registry(injector.get());
+        ServiceLoader serviceLoader = loader.get();
+
+        @SuppressWarnings("rawtypes")
+        Collection<DeployableContainer> containers = serviceLoader.all(DeployableContainer.class);
+
+        if (containers.isEmpty()) {
+            throw new IllegalStateException("There are not any container adapters on the classpath");
+        }
+
+        for (ContainerDef container : event.getContainers()) {
+            if (isCreatingContainer(container, containers)) {
+                if (isEnabled(container)) {
+                    checkMultipleEnabledContainers(container);
+                    reg.create(container, serviceLoader);
+                } else {
+                    log.info("Container is disabled: " + container.getContainerName());
+                }
+            }
+        }
+
+        for (GroupDef group : event.getGroups()) {
+            for (ContainerDef container : group.getGroupContainers()) {
+                if (isCreatingContainer(container, containers)) {
+                    if (isEnabled(container)) {
+                        //TODO add checkMultipleEnabledContainers according to groups
+                        reg.create(container, serviceLoader);
+                    } else {
+                        log.info("Container is disabled: " + container.getContainerName());
+                    }
+                }
+            }
+        }
+
+        registry.set(reg);
+    }
+
+    private static final String ENABLED = "enabled";
+
+    private boolean isEnabled(ContainerDef containerDef) {
+        Map<String, String> props = containerDef.getContainerProperties();
+        return !props.containsKey(ENABLED)
+                || (props.containsKey(ENABLED) && props.get(ENABLED).equals("true"));
+    }
+    
+    private void checkMultipleEnabledContainers(ContainerDef containerDef) {
+        String containerName = containerDef.getContainerName();
+        
+        if (containerName.startsWith("keycloak")) {
+            if (migrationContainer == null) {
+                migrationContainer = containerName;
+            } else {
+                throw new RuntimeException("There is more than one migration container "
+                        + "enabled in arquillian.xml. It has to be enabled at most one. "
+                        + "Do not activate more than one migration profile.");
+            }
+        } else if (containerName.startsWith("auth-server")) {
+            if (authContainer == null) {
+                authContainer = containerName;
+            } else {
+                throw new RuntimeException("There is more than one auth containec enabled "
+                        + "in arquillian.xml. It has to be enabled exactly one. Do not "
+                        + "activate more than one auth profile.");
+            }
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private boolean isCreatingContainer(ContainerDef containerDef, Collection<DeployableContainer> containers) {
+
+        if (hasAdapterImplClassProperty(containerDef)) {
+            if (isClassPresent(getAdapterImplClassValue(containerDef))) {
+                return DeployableContainer.class.isAssignableFrom(
+                        loadClass(getAdapterImplClassValue(containerDef)));
+            }
+        }
+
+        return false;
+    }
+
+    public static boolean hasAdapterImplClassProperty(ContainerDef containerDef) {
+        for (Map.Entry<String, String> entry : containerDef.getContainerProperties().entrySet()) {
+            if (entry.getKey().equals(ADAPTER_IMPL_CONFIG_STRING)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static String getAdapterImplClassValue(ContainerDef containerDef) {
+        return containerDef.getContainerProperties().get(ADAPTER_IMPL_CONFIG_STRING).trim();
+    }
+    public static final String ADAPTER_IMPL_CONFIG_STRING = "adapterImplClass";
+
+    @SuppressWarnings("rawtypes")
+    public static DeployableContainer<?> getContainerAdapter(String adapterImplClass, Collection<DeployableContainer> containers) {
+        Validate.notNullOrEmpty(adapterImplClass, "The value of " + ADAPTER_IMPL_CONFIG_STRING + " can not be a null object "
+                + "nor an empty string!");
+
+        Class<?> foundAdapter = null;
+
+        if (isClassPresent(adapterImplClass)) {
+            foundAdapter = loadClass(adapterImplClass);
+        } else {
+            return null;
+        }
+
+        for (DeployableContainer<?> container : containers) {
+            if (foundAdapter.isInstance(container)) {
+                return container;
+            }
+        }
+
+        return null;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/SecurityActions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/SecurityActions.java
new file mode 100644
index 0000000..941c10a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/SecurityActions.java
@@ -0,0 +1,307 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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.containers;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A set of privileged actions that are not to leak out of this package
+ *
+ * @version $Revision: $
+ */
+final class SecurityActions {
+
+    // -------------------------------------------------------------------------------||
+    // Constructor -------------------------------------------------------------------||
+    // -------------------------------------------------------------------------------||
+    /**
+     * No instantiation
+     */
+    private SecurityActions() {
+        throw new UnsupportedOperationException("No instantiation");
+    }
+
+    // -------------------------------------------------------------------------------||
+    // Utility Methods ---------------------------------------------------------------||
+    // -------------------------------------------------------------------------------||
+    /**
+     * Obtains the Thread Context ClassLoader
+     */
+    static ClassLoader getThreadContextClassLoader() {
+        return AccessController.doPrivileged(GetTcclAction.INSTANCE);
+    }
+
+    static boolean isClassPresent(String name) {
+        try {
+            loadClass(name);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    static Class<?> loadClass(String className) {
+        try {
+            return Class.forName(className, true, getThreadContextClassLoader());
+        } catch (ClassNotFoundException e) {
+            try {
+                return Class.forName(className, true, SecurityActions.class.getClassLoader());
+            } catch (ClassNotFoundException e2) {
+                throw new RuntimeException("Could not load class " + className, e2);
+            }
+        }
+    }
+
+    static <T> T newInstance(final String className, final Class<?>[] argumentTypes, final Object[] arguments,
+            final Class<T> expectedType) {
+        return newInstance(className, argumentTypes, arguments, expectedType, getThreadContextClassLoader());
+    }
+
+    static <T> T newInstance(final String className, final Class<?>[] argumentTypes, final Object[] arguments,
+            final Class<T> expectedType, ClassLoader classLoader) {
+        Class<?> clazz = null;
+        try {
+            clazz = Class.forName(className, false, classLoader);
+        } catch (Exception e) {
+            throw new RuntimeException("Could not load class " + className, e);
+        }
+        Object obj = newInstance(clazz, argumentTypes, arguments);
+        try {
+            return expectedType.cast(obj);
+        } catch (Exception e) {
+            throw new RuntimeException("Loaded class " + className + " is not of expected type " + expectedType, e);
+        }
+    }
+
+    /**
+     * Create a new instance by finding a constructor that matches the
+     * argumentTypes signature using the arguments for instantiation.
+     *
+     * @param className Full classname of class to create
+     * @param argumentTypes The constructor argument types
+     * @param arguments The constructor arguments
+     * @return a new instance
+     * @throws IllegalArgumentException if className, argumentTypes, or
+     * arguments are null
+     * @throws RuntimeException if any exceptions during creation
+     * @author <a href="mailto:aslak@conduct.no">Aslak Knutsen</a>
+     * @author <a href="mailto:andrew.rubinger@jboss.org">ALR</a>
+     */
+    static <T> T newInstance(final Class<T> implClass, final Class<?>[] argumentTypes, final Object[] arguments) {
+        if (implClass == null) {
+            throw new IllegalArgumentException("ImplClass must be specified");
+        }
+        if (argumentTypes == null) {
+            throw new IllegalArgumentException("ArgumentTypes must be specified. Use empty array if no arguments");
+        }
+        if (arguments == null) {
+            throw new IllegalArgumentException("Arguments must be specified. Use empty array if no arguments");
+        }
+        final T obj;
+        try {
+            Constructor<T> constructor = getConstructor(implClass, argumentTypes);
+            if (!constructor.isAccessible()) {
+                constructor.setAccessible(true);
+            }
+            obj = constructor.newInstance(arguments);
+        } catch (Exception e) {
+            throw new RuntimeException("Could not create new instance of " + implClass, e);
+        }
+
+        return obj;
+    }
+
+    /**
+     * Obtains the Constructor specified from the given Class and argument types
+     *
+     * @param clazz
+     * @param argumentTypes
+     * @return
+     * @throws NoSuchMethodException
+     */
+    static <T> Constructor<T> getConstructor(final Class<T> clazz, final Class<?>... argumentTypes)
+            throws NoSuchMethodException {
+        try {
+            return AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<T>>() {
+                @Override
+                public Constructor<T> run() throws NoSuchMethodException {
+                    return clazz.getDeclaredConstructor(argumentTypes);
+                }
+            });
+        } // Unwrap
+        catch (final PrivilegedActionException pae) {
+            final Throwable t = pae.getCause();
+            // Rethrow
+            if (t instanceof NoSuchMethodException) {
+                throw (NoSuchMethodException) t;
+            } else {
+                // No other checked Exception thrown by Class.getConstructor
+                try {
+                    throw (RuntimeException) t;
+                } // Just in case we've really messed up
+                catch (final ClassCastException cce) {
+                    throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t);
+                }
+            }
+        }
+    }
+
+    /**
+     * Set a single Field value
+     *
+     * @param target The object to set it on
+     * @param fieldName The field name
+     * @param value The new value
+     */
+    public static void setFieldValue(final Class<?> source, final Object target, final String fieldName,
+            final Object value) throws NoSuchFieldException {
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                @Override
+                public Void run() throws Exception {
+                    Field field = source.getDeclaredField(fieldName);
+                    if (!field.isAccessible()) {
+                        field.setAccessible(true);
+                    }
+                    field.set(target, value);
+                    return null;
+                }
+            });
+        } // Unwrap
+        catch (final PrivilegedActionException pae) {
+            final Throwable t = pae.getCause();
+            // Rethrow
+            if (t instanceof NoSuchFieldException) {
+                throw (NoSuchFieldException) t;
+            } else {
+                // No other checked Exception thrown by Class.getConstructor
+                try {
+                    throw (RuntimeException) t;
+                } // Just in case we've really messed up
+                catch (final ClassCastException cce) {
+                    throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t);
+                }
+            }
+        }
+    }
+
+    public static List<Field> getFieldsWithAnnotation(final Class<?> source,
+            final Class<? extends Annotation> annotationClass) {
+        List<Field> declaredAccessableFields = AccessController.doPrivileged(new PrivilegedAction<List<Field>>() {
+            @Override
+            public List<Field> run() {
+                List<Field> foundFields = new ArrayList<Field>();
+                Class<?> nextSource = source;
+                while (nextSource != Object.class) {
+                    for (Field field : nextSource.getDeclaredFields()) {
+                        if (field.isAnnotationPresent(annotationClass)) {
+                            if (!field.isAccessible()) {
+                                field.setAccessible(true);
+                            }
+                            foundFields.add(field);
+                        }
+                    }
+                    nextSource = nextSource.getSuperclass();
+                }
+                return foundFields;
+            }
+        });
+        return declaredAccessableFields;
+    }
+
+    public static List<Method> getMethodsWithAnnotation(final Class<?> source,
+            final Class<? extends Annotation> annotationClass) {
+        List<Method> declaredAccessableMethods = AccessController.doPrivileged(new PrivilegedAction<List<Method>>() {
+            @Override
+            public List<Method> run() {
+                List<Method> foundMethods = new ArrayList<Method>();
+                Class<?> nextSource = source;
+                while (nextSource != Object.class) {
+                    for (Method method : nextSource.getDeclaredMethods()) {
+                        if (method.isAnnotationPresent(annotationClass)) {
+                            if (!method.isAccessible()) {
+                                method.setAccessible(true);
+                            }
+                            foundMethods.add(method);
+                        }
+                    }
+                    nextSource = nextSource.getSuperclass();
+                }
+                return foundMethods;
+            }
+        });
+        return declaredAccessableMethods;
+    }
+
+    static String getProperty(final String key) {
+        try {
+            String value = AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
+                @Override
+                public String run() {
+                    return System.getProperty(key);
+                }
+            });
+            return value;
+        } // Unwrap
+        catch (final PrivilegedActionException pae) {
+            final Throwable t = pae.getCause();
+            // Rethrow
+            if (t instanceof SecurityException) {
+                throw (SecurityException) t;
+            }
+            if (t instanceof NullPointerException) {
+                throw (NullPointerException) t;
+            } else if (t instanceof IllegalArgumentException) {
+                throw (IllegalArgumentException) t;
+            } else {
+                // No other checked Exception thrown by System.getProperty
+                try {
+                    throw (RuntimeException) t;
+                } // Just in case we've really messed up
+                catch (final ClassCastException cce) {
+                    throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t);
+                }
+            }
+        }
+    }
+
+    // -------------------------------------------------------------------------------||
+    // Inner Classes -----------------------------------------------------------------||
+    // -------------------------------------------------------------------------------||
+    /**
+     * Single instance to get the TCCL
+     */
+    private enum GetTcclAction implements PrivilegedAction<ClassLoader> {
+
+        INSTANCE;
+
+        @Override
+        public ClassLoader run() {
+            return Thread.currentThread().getContextClassLoader();
+        }
+
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java
new file mode 100644
index 0000000..ffb3e0c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java
@@ -0,0 +1,187 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.jboss.arquillian.container.spi.event.StartSuiteContainers;
+import org.jboss.arquillian.container.spi.event.StopSuiteContainers;
+import org.jboss.arquillian.container.test.api.ContainerController;
+import org.jboss.arquillian.core.api.Event;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.InstanceProducer;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.core.api.annotation.Observes;
+import org.jboss.arquillian.test.spi.annotation.ClassScoped;
+import org.jboss.arquillian.test.spi.annotation.SuiteScoped;
+import org.jboss.arquillian.container.spi.event.container.AfterStart;
+import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
+import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;
+import org.jboss.logging.Logger;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.models.Constants;
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
+import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
+
+/**
+ *
+ * @author tkyjovsk
+ * @author vramik
+ */
+public class ContainersTestEnricher {
+
+    protected final Logger log = Logger.getLogger(this.getClass());
+    
+    @Inject
+    private Instance<ContainerController> containerController;
+
+    @Inject
+    private Event<StopSuiteContainers> stopSuiteContainers;
+    
+    private String appServerQualifier;
+
+    private static final String AUTH_SERVER_CONTAINER_PROPERTY = "auth.server.container";
+    private static final String AUTH_SERVER_CONTAINER_DEFAULT = "auth-server-undertow";
+
+    @Inject
+    @SuiteScoped
+    private InstanceProducer<SuiteContext> suiteContext;
+
+    @Inject
+    @ClassScoped
+    private InstanceProducer<TestContext> testContext;
+
+    @Inject
+    @ClassScoped
+    private InstanceProducer<Keycloak> adminClient;
+
+    private ContainerController controller;
+
+    private final boolean migrationTests = System.getProperty("migration", "false").equals("true");
+    private boolean alreadyStopped = false;
+
+    public void startSuiteContainers(@Observes(precedence = 1) StartSuiteContainers event) {
+        if (migrationTests) {
+            log.info("\n### Starting keycloak with previous version ###\n");
+        }
+    }
+
+    public void stopMigrationContainer(@Observes AfterStart event) {
+        if (migrationTests && !alreadyStopped) {
+            log.info("\n### Stopping keycloak with previous version ###\n");
+            stopSuiteContainers.fire(new StopSuiteContainers());
+        }
+        alreadyStopped = true;
+    }
+    
+    public void beforeSuite(@Observes BeforeSuite event) {
+        suiteContext.set(new SuiteContext());
+    }
+
+    public void startContainers(@Observes(precedence = -1) BeforeClass event) {
+        controller = containerController.get();
+
+        Class testClass = event.getTestClass().getJavaClass();
+        appServerQualifier = getAppServerQualifier(testClass);
+
+        if (!controller.isStarted(appServerQualifier)) {
+            log.info("\nSTARTING APP SERVER: " + appServerQualifier + "\n");
+            controller.start(appServerQualifier);
+            log.info("");
+        }
+
+        initializeTestContext(testClass);
+        initializeAdminClient();
+    }
+
+    private void initializeTestContext(Class testClass) {
+        String authServerContextRootStr = getAuthServerContextRootFromSystemProperty();
+        String appServerContextRootStr = isRelative(testClass)
+                ? authServerContextRootStr
+                : getAppServerContextRootFromSystemProperty();
+        try {
+            URL authServerContextRoot = new URL(authServerContextRootStr);
+            URL appServerContextRoot = new URL(appServerContextRootStr);
+
+            testContext.set(new TestContext(authServerContextRoot, appServerContextRoot));
+
+        } catch (MalformedURLException ex) {
+            throw new IllegalStateException("Malformed url.", ex);
+        }
+    }
+
+    private void initializeAdminClient() {
+        adminClient.set(Keycloak.getInstance(
+                getAuthServerContextRootFromSystemProperty() + "/auth",
+                MASTER, ADMIN, ADMIN, Constants.ADMIN_CONSOLE_CLIENT_ID));
+    }
+
+    /**
+     *
+     * @param testClass
+     * @param annotationClass
+     * @return testClass or the nearest superclass of testClass annotated with
+     * annotationClass
+     */
+    public static Class getNearestSuperclassWithAnnotation(Class testClass, Class annotationClass) {
+        return testClass.isAnnotationPresent(annotationClass) ? testClass
+                : (testClass.getSuperclass().equals(Object.class) ? null // stop recursion
+                        : getNearestSuperclassWithAnnotation(testClass.getSuperclass(), annotationClass)); // continue recursion
+    }
+
+    public static String getAuthServerQualifier() {
+        return System.getProperty(
+                AUTH_SERVER_CONTAINER_PROPERTY,
+                AUTH_SERVER_CONTAINER_DEFAULT);
+    }
+
+    public static String getAppServerQualifier(Class testClass) {
+        Class<? extends ContainersTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class);
+
+        String appServerQ = (annotatedClass == null ? null
+                : annotatedClass.getAnnotation(AppServerContainer.class).value());
+
+        return appServerQ == null || appServerQ.isEmpty()
+                ? getAuthServerQualifier() // app server == auth server
+                : appServerQ;
+    }
+
+    public static boolean hasAppServerContainerAnnotation(Class testClass) {
+        return getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class) != null;
+    }
+
+    public static boolean isRelative(Class testClass) {
+        return getAppServerQualifier(testClass).equals(getAuthServerQualifier());
+    }
+
+    public static String getAdapterLibsLocationProperty(Class testClass) {
+        Class<? extends ContainersTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AdapterLibsLocationProperty.class);
+        return (annotatedClass == null ? null
+                : annotatedClass.getAnnotation(AdapterLibsLocationProperty.class).value());
+    }
+
+    public static boolean isWildflyAppServer(Class testClass) {
+        return getAppServerQualifier(testClass).contains("wildfly");
+    }
+
+    public static boolean isTomcatAppServer(Class testClass) {
+        return getAppServerQualifier(testClass).contains("tomcat");
+    }
+
+    public static boolean isOSGiAppServer(Class testClass) {
+        String q = getAppServerQualifier(testClass);
+        return q.contains("karaf") || q.contains("fuse");
+    }
+
+    public static String getAuthServerContextRootFromSystemProperty() {
+        // TODO find if this can be extracted from ARQ metadata instead of System properties
+        return "http://localhost:" + Integer.parseInt(
+                System.getProperty("auth.server.http.port", "8180"));
+    }
+
+    public static String getAppServerContextRootFromSystemProperty() {
+        return "http://localhost:" + Integer.parseInt(
+                System.getProperty("app.server.http.port", "8280"));
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
new file mode 100644
index 0000000..0a965d8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
@@ -0,0 +1,140 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.apache.tools.ant.DirectoryScanner;
+import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
+import org.jboss.arquillian.test.spi.TestClass;
+import org.jboss.logging.Logger;
+import org.jboss.logging.Logger.Level;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.keycloak.representations.adapters.config.BaseAdapterConfig;
+import static org.keycloak.testsuite.arquillian.ContainersTestEnricher.*;
+import org.keycloak.testsuite.adapter.AdapterLibsMode;
+import static org.keycloak.testsuite.util.IOUtil.loadJson;;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
+
+    public static final String REALM_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
+
+    protected final Logger log = org.jboss.logging.Logger.getLogger(this.getClass());
+
+    public static final String WEBXML_PATH = "/WEB-INF/web.xml";
+    public static final String ADAPTER_CONFIG_PATH = "/WEB-INF/keycloak.json";
+    public static final String ADAPTER_CONFIG_PATH_TENANT1 = "/WEB-INF/classes/tenant1-keycloak.json";
+    public static final String ADAPTER_CONFIG_PATH_TENANT2 = "/WEB-INF/classes/tenant2-keycloak.json";
+    public static final String ADAPTER_CONFIG_PATH_JS = "/keycloak.json";
+
+    @Override
+    public void process(Archive<?> archive, TestClass testClass) {
+        log.info("Processing archive " + archive.getName());
+//        if (isAdapterTest(testClass)) {
+        modifyAdapterConfigs(archive, testClass);
+        attachKeycloakLibs(archive, testClass);
+        modifyWebXml(archive, testClass);
+//        } else {
+//            log.info(testClass.getJavaClass().getSimpleName() + " is not an AdapterTest");
+//        }
+    }
+    
+    public static boolean isAdapterTest(TestClass testClass) {
+        return hasAppServerContainerAnnotation(testClass.getJavaClass());
+    }
+
+    protected void modifyAdapterConfigs(Archive<?> archive, TestClass testClass) {
+        boolean relative = isRelative(testClass.getJavaClass());
+        modifyAdapterConfig(archive, ADAPTER_CONFIG_PATH, relative);
+        modifyAdapterConfig(archive, ADAPTER_CONFIG_PATH_TENANT1, relative);
+        modifyAdapterConfig(archive, ADAPTER_CONFIG_PATH_TENANT2, relative);
+        modifyAdapterConfig(archive, ADAPTER_CONFIG_PATH_JS, relative);
+    }
+
+    protected void modifyAdapterConfig(Archive<?> archive, String adapterConfigPath, boolean relative) {
+        if (archive.contains(adapterConfigPath)) {
+            log.info("Modifying adapter config " + adapterConfigPath + " in " + archive.getName());
+            try {
+                BaseAdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
+                        .getAsset().openStream(), BaseAdapterConfig.class);
+
+                log.info(" setting " + (relative ? "" : "non-") + "relative auth-server-url");
+                if (relative) {
+                    adapterConfig.setAuthServerUrl("/auth");
+//                ac.setRealmKey(null); // TODO verify if realm key is required for relative scneario
+                } else {
+                    adapterConfig.setAuthServerUrl(getAuthServerContextRootFromSystemProperty() + "/auth");
+                    adapterConfig.setRealmKey(REALM_KEY);
+                }
+
+                archive.add(new StringAsset(JsonSerialization.writeValueAsPrettyString(adapterConfig)),
+                        adapterConfigPath);
+
+            } catch (IOException ex) {
+                log.log(Level.FATAL, "Cannot serialize adapter config to JSON.", ex);
+            }
+        }
+    }
+
+    protected void attachKeycloakLibs(Archive<?> archive, TestClass testClass) {
+        AdapterLibsMode adapterType = AdapterLibsMode.getByType(System.getProperty("adapter.libs.mode",
+                AdapterLibsMode.PROVIDED.getType()));
+        log.info("Adapter type: " + adapterType);
+        if (adapterType.equals(AdapterLibsMode.BUNDLED)) {
+            log.info("Attaching keycloak adapter libs to " + archive.getName());
+
+            String libsLocationProperty = getAdapterLibsLocationProperty(testClass.getJavaClass());
+            assert libsLocationProperty != null;
+            File libsLocation = new File(System.getProperty(libsLocationProperty));
+            assert libsLocation.exists();
+            log.info("Libs location: " + libsLocation.getPath());
+
+            WebArchive war = (WebArchive) archive;
+
+            for (File lib : getAdapterLibs(libsLocation)) {
+                log.info(" attaching: " + lib.getName());
+                war.addAsLibrary(lib);
+            }
+        } else {
+            log.info("Expecting keycloak adapter libs to be provided by the server.");
+        }
+    }
+
+    DirectoryScanner scanner = new DirectoryScanner();
+
+    protected List<File> getAdapterLibs(File adapterLibsLocation) {
+        assert adapterLibsLocation.exists();
+        List<File> libs = new ArrayList<>();
+        scanner.setBasedir(adapterLibsLocation);
+        scanner.setIncludes(new String[]{"**/*jar"});
+        scanner.scan();
+        for (String lib : scanner.getIncludedFiles()) {
+            libs.add(new File(adapterLibsLocation, lib));
+        }
+        return libs;
+    }
+
+    protected void modifyWebXml(Archive<?> archive, TestClass testClass) {
+        if (isTomcatAppServer(testClass.getJavaClass())) {
+            try {
+                String webXmlContent = IOUtils.toString(
+                        archive.get(WEBXML_PATH).getAsset().openStream());
+
+                webXmlContent = webXmlContent.replace("<auth-method>KEYCLOAK</auth-method>", "<auth-method>BASIC</auth-method>");
+
+                archive.add(new StringAsset((webXmlContent)), WEBXML_PATH);
+            } catch (IOException ex) {
+                throw new RuntimeException("Cannot load web.xml from archive.");
+            }
+        }
+    }
+
+}
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
new file mode 100644
index 0000000..faaeb81
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java
@@ -0,0 +1,40 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.util.List;
+import org.jboss.arquillian.container.spi.client.deployment.DeploymentDescription;
+import org.jboss.arquillian.container.spi.client.deployment.TargetDescription;
+import org.jboss.arquillian.container.test.impl.client.deployment.AnnotationDeploymentScenarioGenerator;
+import org.jboss.arquillian.test.spi.TestClass;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.arquillian.ContainersTestEnricher.*;
+
+/**
+ * Changes target container for all Arquillian deployments based on value of
+ * @AppServerContainer.
+ *
+ * @author tkyjovsk
+ */
+public class DeploymentTargetModifier extends AnnotationDeploymentScenarioGenerator {
+
+    protected final Logger log = Logger.getLogger(this.getClass());
+
+    @Override
+    public List<DeploymentDescription> generate(TestClass testClass) {
+        List<DeploymentDescription> deployments = super.generate(testClass);
+
+        String appServerQualifier = getAppServerQualifier(
+                testClass.getJavaClass());
+
+        if (appServerQualifier != null && !appServerQualifier.isEmpty()) {
+            for (DeploymentDescription deployment : deployments) {
+                if (deployment.getTarget() == null || !deployment.getTarget().getName().equals(appServerQualifier)) {
+                    log.debug("Setting target container for " + deployment.getName() + ": " + appServerQualifier);
+                    deployment.setTarget(new TargetDescription(appServerQualifier));
+                }
+            }
+        }
+
+        return deployments;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JBossJiraParser.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JBossJiraParser.java
new file mode 100644
index 0000000..ea606b8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JBossJiraParser.java
@@ -0,0 +1,43 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.testsuite.arquillian.jira;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+
+/**
+ *
+ * @author <a href="mailto:pmensik@redhat.com">Petr Mensik</a>
+ */
+public class JBossJiraParser {
+
+    private static final String JBOSS_TRACKER_REST_URL = "https://issues.jboss.org/rest/api/latest/issue/";
+
+    public static boolean isIssueClosed(String issueId) {
+		Status issueStatus;
+		try {
+			issueStatus = getIssueStatus(issueId);
+		} catch(Exception e) {
+			issueStatus = Status.CLOSED; //let the test run in case there is no connection
+		}
+        return issueStatus == Status.CLOSED || issueStatus == Status.RESOLVED;
+    }
+
+    private static Status getIssueStatus(String issueId) throws Exception {
+		Client client = ClientBuilder.newClient();
+        WebTarget target = client.target(JBOSS_TRACKER_REST_URL);
+        String json = target.path(issueId).request().accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
+        JsonObject jsonObject = new Gson().fromJson(json, JsonElement.class).getAsJsonObject();
+        String status = jsonObject.getAsJsonObject("fields").getAsJsonObject("status").get("name").getAsString();
+        client.close();
+        return Status.getByStatus(status);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Jira.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Jira.java
new file mode 100644
index 0000000..961ae82
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Jira.java
@@ -0,0 +1,28 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.testsuite.arquillian.jira;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Value should contain name of the issue listed in JBoss JIRA (like
+ * KEYCLOAK-1234), it can also contain multiple names separated by coma.
+ *
+ * @author <a href="mailto:pmensik@redhat.com">Petr Mensik</a>
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Documented
+public @interface Jira {
+
+    String value();
+	boolean enabled() default true;
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JiraTestExecutionDecider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JiraTestExecutionDecider.java
new file mode 100644
index 0000000..fa3c571
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JiraTestExecutionDecider.java
@@ -0,0 +1,61 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.testsuite.arquillian.jira;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import org.jboss.arquillian.test.spi.execution.ExecutionDecision;
+import org.jboss.arquillian.test.spi.execution.TestExecutionDecider;
+
+import static org.keycloak.testsuite.arquillian.jira.JBossJiraParser.isIssueClosed;
+
+/**
+ *
+ * @author <a href="mailto:pmensik@redhat.com">Petr Mensik</a>
+ */
+public class JiraTestExecutionDecider implements TestExecutionDecider {
+
+	private static Map<String, Boolean> cache = new HashMap<String, Boolean>();
+
+	@Override
+	public ExecutionDecision decide(Method method) {
+		Jira jiraAnnotation = method.getAnnotation(Jira.class);
+		if (jiraAnnotation != null && jiraAnnotation.enabled()) {
+			boolean executeTest = true;
+			String[] issueIds = getIssuesId(jiraAnnotation.value());
+			for (String issueId : issueIds) {
+				if (cache.containsKey(issueId)) {
+					executeTest = cache.get(issueId);
+				} else {
+					if (isIssueClosed(issueId)) {
+						cache.put(issueId, true);
+					} else {
+						executeTest = false;
+						cache.put(issueId, false);
+					}
+				}
+			}
+
+			if (executeTest) {
+				return ExecutionDecision.execute();
+			} else {
+				return ExecutionDecision.dontExecute("Issue is still opened, therefore skipping the test " + method.getName());
+			}
+		}
+		return ExecutionDecision.execute();
+	}
+
+	private String[] getIssuesId(String value) {
+		return value.replaceAll("\\s+", "").split(",");
+	}
+
+	@Override
+	public int precedence() {
+		return 0;
+	}
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Status.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Status.java
new file mode 100644
index 0000000..47f707a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Status.java
@@ -0,0 +1,36 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.testsuite.arquillian.jira;
+
+/**
+ *
+ * @author <a href="mailto:pmensik@redhat.com">Petr Mensik</a>
+ */
+public enum Status {
+
+    OPEN("Open"), CLOSED("Closed"), PULL_REQUEST_SENT("Pull Request Sent"), REOPENED("Reopened"),
+    RESOLVED("Resolved"), CODING_IN_PROGRESS("Coding In Progress ");
+
+    private String status;
+
+    private Status(String status) {
+        this.status = status;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public static Status getByStatus(String status) {
+        for (Status s : Status.values()) {
+            if (s.getStatus().equals(status)) {
+                return s;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java
new file mode 100644
index 0000000..cf25d05
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java
@@ -0,0 +1,49 @@
+package org.keycloak.testsuite.arquillian;
+
+import org.keycloak.testsuite.arquillian.provider.URLProvider;
+import org.keycloak.testsuite.arquillian.provider.SuiteContextProvider;
+import org.keycloak.testsuite.arquillian.provider.TestContextProvider;
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.container.test.impl.enricher.resource.URLResourceProvider;
+import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
+import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator;
+import org.jboss.arquillian.core.spi.LoadableExtension;
+import org.jboss.arquillian.graphene.location.CustomizableURLResourceProvider;
+import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
+import org.jboss.arquillian.test.spi.execution.TestExecutionDecider;
+import org.keycloak.testsuite.arquillian.jira.JiraTestExecutionDecider;
+import org.keycloak.testsuite.arquillian.provider.AdminClientProvider;
+import org.keycloak.testsuite.arquillian.undertow.CustomUndertowContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class KeycloakArquillianExtension implements LoadableExtension {
+
+    @Override
+    public void register(ExtensionBuilder builder) {
+
+        builder
+                .service(ResourceProvider.class, SuiteContextProvider.class)
+                .service(ResourceProvider.class, TestContextProvider.class)
+                .service(ResourceProvider.class, AdminClientProvider.class);
+
+        builder
+                .service(DeploymentScenarioGenerator.class, DeploymentTargetModifier.class)
+                .service(ApplicationArchiveProcessor.class, DeploymentArchiveProcessor.class)
+                .observer(ContainersTestEnricher.class);
+
+        builder
+                .service(DeployableContainer.class, CustomUndertowContainer.class);
+
+        builder
+                .service(TestExecutionDecider.class, JiraTestExecutionDecider.class);
+
+        builder
+                .override(ResourceProvider.class, URLResourceProvider.class, URLProvider.class)
+                .override(ResourceProvider.class, CustomizableURLResourceProvider.class, URLProvider.class);
+
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/AdminClientProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/AdminClientProvider.java
new file mode 100644
index 0000000..8e7c3ac
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/AdminClientProvider.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.arquillian.provider;
+
+import java.lang.annotation.Annotation;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
+import org.keycloak.admin.client.Keycloak;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminClientProvider implements ResourceProvider {
+
+    @Inject
+    Instance<Keycloak> adminClient;
+    
+    @Override
+    public boolean canProvide(Class<?> type) {
+        return Keycloak.class.isAssignableFrom(type);
+    }
+
+    @Override
+    public Object lookup(ArquillianResource resource, Annotation... qualifiers) {
+        return adminClient.get();
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/SuiteContextProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/SuiteContextProvider.java
new file mode 100644
index 0000000..2755688
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/SuiteContextProvider.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.arquillian.provider;
+
+import org.keycloak.testsuite.arquillian.SuiteContext;
+import java.lang.annotation.Annotation;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class SuiteContextProvider implements ResourceProvider {
+
+    @Inject
+    Instance<SuiteContext> suiteContext;
+
+    @Override
+    public boolean canProvide(Class<?> type) {
+        return SuiteContext.class.isAssignableFrom(type);
+    }
+
+    @Override
+    public Object lookup(ArquillianResource resource, Annotation... qualifiers) {
+        return suiteContext.get();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/TestContextProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/TestContextProvider.java
new file mode 100644
index 0000000..ebe7326
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/TestContextProvider.java
@@ -0,0 +1,30 @@
+package org.keycloak.testsuite.arquillian.provider;
+
+import org.keycloak.testsuite.arquillian.TestContext;
+import java.lang.annotation.Annotation;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class TestContextProvider implements ResourceProvider {
+
+    @Inject
+    Instance<TestContext> testContext;
+
+    @Override
+    public boolean canProvide(Class<?> type) {
+        return TestContext.class.isAssignableFrom(type);
+    }
+
+    @Override
+    @ClassInjection
+    public Object lookup(ArquillianResource resource, Annotation... qualifiers) {
+        return testContext.get();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java
new file mode 100644
index 0000000..dd31483
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java
@@ -0,0 +1,79 @@
+package org.keycloak.testsuite.arquillian.provider;
+
+import org.keycloak.testsuite.arquillian.TestContext;
+import java.lang.annotation.Annotation;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+import org.jboss.arquillian.container.test.impl.enricher.resource.URLResourceProvider;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.logging.Logger;
+import org.jboss.logging.Logger.Level;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContext;
+import org.keycloak.testsuite.arquillian.annotation.AuthServerContext;
+
+public class URLProvider extends URLResourceProvider {
+
+    protected final Logger log = Logger.getLogger(this.getClass());
+
+    public static final String LOCALHOST_ADDRESS = "127.0.0.1";
+    public static final String LOCALHOST_HOSTNAME = "localhost";
+
+    @Inject
+    Instance<TestContext> testContext;
+
+    private static final Set<String> fixedUrls = new HashSet<>();
+
+    @Override
+    public Object doLookup(ArquillianResource resource, Annotation... qualifiers) {
+        URL url = (URL) super.doLookup(resource, qualifiers);
+
+        // fix injected URL
+        if (url != null) {
+            try {
+                url = fixLocalhost(url);
+                url = removeTrailingSlash(url);
+            } catch (MalformedURLException ex) {
+                log.log(Level.FATAL, null, ex);
+            }
+
+            if (!fixedUrls.contains(url.toString())) {
+                fixedUrls.add(url.toString());
+                log.debug("Fixed injected @ArquillianResource URL to: " + url);
+            }
+        }
+
+        // inject context roots if annotation present
+        for (Annotation a : qualifiers) {
+            if (AuthServerContext.class.isAssignableFrom(a.annotationType())) {
+                return testContext.get().getAuthServerContextRoot();
+            }
+            if (AppServerContext.class.isAssignableFrom(a.annotationType())) {
+                return testContext.get().getAppServerContextRoot();
+            }
+        }
+
+        return url;
+    }
+
+    public URL fixLocalhost(URL url) throws MalformedURLException {
+        URL fixedUrl = url;
+        if (url.getHost().contains(LOCALHOST_ADDRESS)) {
+            fixedUrl = new URL(fixedUrl.toExternalForm().replace(LOCALHOST_ADDRESS, LOCALHOST_HOSTNAME));
+        }
+        return fixedUrl;
+    }
+
+    public URL removeTrailingSlash(URL url) throws MalformedURLException {
+        URL urlWithoutSlash = url;
+        String urlS = url.toExternalForm();
+        if (urlS.endsWith("/")) {
+            urlWithoutSlash = new URL(urlS.substring(0, urlS.length() - 1));
+        }
+        return urlWithoutSlash;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java
new file mode 100644
index 0000000..589c316
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.util.HashMap;
+import java.util.Map;
+import static org.keycloak.testsuite.util.MailServerConfiguration.*;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public final class SuiteContext {
+
+    private boolean adminPasswordUpdated;
+    private final Map<String, String> smtpServer = new HashMap<>();
+    
+    public SuiteContext() {
+        this.adminPasswordUpdated = false;
+        smtpServer.put("from", FROM);
+        smtpServer.put("host", HOST);
+        smtpServer.put("port", PORT);
+    }
+
+    public boolean isAdminPasswordUpdated() {
+        return adminPasswordUpdated;
+    }
+
+    public void setAdminPasswordUpdated(boolean adminPasswordUpdated) {
+        this.adminPasswordUpdated = adminPasswordUpdated;
+    }
+
+    public Map<String, String> getSmtpServer() {
+        return smtpServer;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java
new file mode 100644
index 0000000..850c787
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java
@@ -0,0 +1,50 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.net.URL;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public final class TestContext {
+
+    private URL authServerContextRoot;
+    private URL appServerContextRoot;
+
+    private boolean adminLoggedIn;
+
+    public TestContext() {
+        this.adminLoggedIn = false;
+    }
+
+    public TestContext(URL authServerContextRoot, URL appServerContextRoot) {
+        this();
+        this.authServerContextRoot = authServerContextRoot;
+        this.appServerContextRoot = appServerContextRoot;
+    }
+
+    public URL getAuthServerContextRoot() {
+        return authServerContextRoot;
+    }
+
+    public URL getAppServerContextRoot() {
+        return appServerContextRoot;
+    }
+
+    public boolean isAdminLoggedIn() {
+        return adminLoggedIn;
+    }
+
+    public void setAdminLoggedIn(boolean adminLoggedIn) {
+        this.adminLoggedIn = adminLoggedIn;
+    }
+
+    public void setAuthServerContextRoot(URL authServerContextRoot) {
+        this.authServerContextRoot = authServerContextRoot;
+    }
+
+    public void setAppServerContextRoot(URL appServerContextRoot) {
+        this.appServerContextRoot = appServerContextRoot;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainer.java
new file mode 100644
index 0000000..e2dc4db
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainer.java
@@ -0,0 +1,144 @@
+package org.keycloak.testsuite.arquillian.undertow;
+
+import io.undertow.Undertow;
+import io.undertow.servlet.Servlets;
+import io.undertow.servlet.api.DefaultServletConfig;
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.FilterInfo;
+import io.undertow.servlet.api.ServletInfo;
+
+import java.util.Collection;
+import java.util.Map;
+import javax.servlet.DispatcherType;
+
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+
+import org.jboss.arquillian.container.spi.client.container.DeploymentException;
+import org.jboss.arquillian.container.spi.client.container.LifecycleException;
+import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.HTTPContext;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
+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.descriptor.api.Descriptor;
+import org.jboss.shrinkwrap.undertow.api.UndertowWebArchive;
+import org.keycloak.services.filters.ClientConnectionFilter;
+import org.keycloak.services.filters.KeycloakSessionServletFilter;
+import org.keycloak.services.resources.KeycloakApplication;
+
+public class CustomUndertowContainer implements DeployableContainer<CustomUndertowContainerConfiguration> {
+
+    protected final Logger log = Logger.getLogger(this.getClass());
+    
+    private UndertowJaxrsServer undertow;
+    private CustomUndertowContainerConfiguration configuration;
+
+    private DeploymentInfo createAuthServerDeploymentInfo() {
+        ResteasyDeployment deployment = new ResteasyDeployment();
+        deployment.setApplicationClass(KeycloakApplication.class.getName());
+
+        DeploymentInfo di = undertow.undertowDeployment(deployment);
+        di.setClassLoader(getClass().getClassLoader());
+        di.setContextPath("/auth");
+        di.setDeploymentName("Keycloak");
+
+        di.setDefaultServletConfig(new DefaultServletConfig(true));
+        di.addWelcomePage("theme/keycloak/welcome/resources/index.html");
+
+        FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
+        di.addFilter(filter);
+        di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
+
+        FilterInfo connectionFilter = Servlets.filter("ClientConnectionFilter", ClientConnectionFilter.class);
+        di.addFilter(connectionFilter);
+        di.addFilterUrlMapping("ClientConnectionFilter", "/*", DispatcherType.REQUEST);
+
+        return di;
+    }
+
+    public DeploymentInfo getDeplotymentInfoFromArchive(Archive<?> archive) {
+        if (archive instanceof UndertowWebArchive) {
+            return ((UndertowWebArchive) archive).getDeploymentInfo();
+        } else {
+            throw new IllegalArgumentException("UndertowContainer only supports UndertowWebArchive or WebArchive.");
+        }
+    }
+
+    private HTTPContext createHttpContextForDeploymentInfo(DeploymentInfo deploymentInfo) {
+        HTTPContext httpContext = new HTTPContext(configuration.getBindAddress(), configuration.getBindHttpPort());
+        final Map<String, ServletInfo> servlets = deploymentInfo.getServlets();
+        final Collection<ServletInfo> servletsInfo = servlets.values();
+        for (ServletInfo servletInfo : servletsInfo) {
+            httpContext.add(new Servlet(servletInfo.getName(), deploymentInfo.getContextPath()));
+        }
+        return httpContext;
+    }
+
+    @Override
+    public ProtocolMetaData deploy(Archive<?> archive) throws DeploymentException {
+        DeploymentInfo di = getDeplotymentInfoFromArchive(archive);
+        undertow.deploy(di);
+        return new ProtocolMetaData().addContext(
+                createHttpContextForDeploymentInfo(di));
+    }
+
+    @Override
+    public void deploy(Descriptor descriptor) throws DeploymentException {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    @Override
+    public Class<CustomUndertowContainerConfiguration> getConfigurationClass() {
+        return CustomUndertowContainerConfiguration.class;
+    }
+
+    @Override
+    public ProtocolDescription getDefaultProtocol() {
+        return new ProtocolDescription("Servlet 3.1");
+    }
+
+    @Override
+    public void setup(
+            CustomUndertowContainerConfiguration undertowContainerConfiguration) {
+        this.configuration = undertowContainerConfiguration;
+    }
+
+    @Override
+    public void start() throws LifecycleException {
+        log.info("Starting auth server on embedded Undertow.");
+        long start = System.currentTimeMillis();
+
+        if (undertow == null) {
+            undertow = new UndertowJaxrsServer();
+        }
+        undertow.start(Undertow.builder()
+                .addHttpListener(configuration.getBindHttpPort(), configuration.getBindAddress())
+                .setWorkerThreads(configuration.getWorkerThreads())
+                .setIoThreads(configuration.getWorkerThreads() / 8)
+        );
+
+        undertow.deploy(createAuthServerDeploymentInfo());
+
+        log.info("Auth server started in " + (System.currentTimeMillis() - start) + " ms\n");
+    }
+
+    @Override
+    public void stop() throws LifecycleException {
+        log.info("Stopping auth server.");
+        undertow.stop();
+    }
+
+    @Override
+    public void undeploy(Archive<?> archive) throws DeploymentException {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    @Override
+    public void undeploy(Descriptor descriptor) throws DeploymentException {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainerConfiguration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainerConfiguration.java
new file mode 100644
index 0000000..5d87119
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainerConfiguration.java
@@ -0,0 +1,35 @@
+package org.keycloak.testsuite.arquillian.undertow;
+
+import org.arquillian.undertow.UndertowContainerConfiguration;
+import org.jboss.arquillian.container.spi.ConfigurationException;
+
+public class CustomUndertowContainerConfiguration extends UndertowContainerConfiguration {
+
+    private int workerThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2) * 8;
+    private String resourcesHome;
+
+    public int getWorkerThreads() {
+        return workerThreads;
+    }
+
+    public void setWorkerThreads(int workerThreads) {
+        this.workerThreads = workerThreads;
+    }
+
+    public String getResourcesHome() {
+        return resourcesHome;
+    }
+
+    public void setResourcesHome(String resourcesHome) {
+        this.resourcesHome = resourcesHome;
+    }
+
+    @Override
+    public void validate() throws ConfigurationException {
+        super.validate();
+        
+        // TODO validate workerThreads
+        
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Account.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Account.java
new file mode 100644
index 0000000..10cc7e5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Account.java
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.auth.page.account;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author Petr Mensik
+ */
+public class Account extends AccountManagement {
+    
+    @FindBy(id = "username")
+    private WebElement username;
+
+    @FindBy(id = "email")
+    private WebElement email;
+
+    @FindBy(id = "lastName")
+    private WebElement lastName;
+
+    @FindBy(id = "firstName")
+    private WebElement firstName;
+
+    public String getUsername() {
+        return username.getAttribute("value");
+    }
+
+    public String getEmail() {
+        return email.getAttribute("value");
+    }
+
+    public String getFirstName() {
+        return firstName.getAttribute("value");
+    }
+
+    public String getLastName() {
+        return lastName.getAttribute("value");
+    }
+
+    public Account setEmail(String value) {
+        email.clear();
+        email.sendKeys(value);
+        return this;
+    }
+
+    public Account setFirstName(String value) {
+        firstName.clear();
+        firstName.sendKeys(value);
+        return this;
+    }
+
+    public Account setLastName(String value) {
+        lastName.clear();
+        lastName.sendKeys(value);
+        return this;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java
new file mode 100644
index 0000000..f78d31a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java
@@ -0,0 +1,59 @@
+package org.keycloak.testsuite.auth.page.account;
+
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElementNotPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AccountFields extends Form {
+
+    @FindBy(id = "username")
+    private WebElement usernameInput;
+    @FindBy(id = "email")
+    private WebElement emailInput;
+    @FindBy(id = "firstName")
+    private WebElement firstNameInput;
+    @FindBy(id = "lastName")
+    private WebElement lastNameInput;
+
+    public void setUsername(String username) {
+        Form.setInputValue(usernameInput, username);
+    }
+
+    public AccountFields setEmail(String email) {
+        Form.setInputValue(emailInput, email);
+        return this;
+    }
+
+    public AccountFields setFirstName(String firstName) {
+        Form.setInputValue(firstNameInput, firstName);
+        return this;
+    }
+
+    public AccountFields setLastName(String lastName) {
+        Form.setInputValue(lastNameInput, lastName);
+        return this;
+    }
+
+    public void setValues(UserRepresentation user) {
+        setUsername(user.getUsername());
+        setEmail(user.getEmail());
+        setFirstName(user.getFirstName());
+        setLastName(user.getLastName());
+    }
+
+    public void waitForUsernameInputPresent() {
+        waitAjaxForElement(usernameInput);
+    }
+
+    public void waitForUsernameInputNotPresent() {
+        waitAjaxForElementNotPresent(usernameInput);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/ContactInfoFields.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/ContactInfoFields.java
new file mode 100644
index 0000000..6d1a96c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/ContactInfoFields.java
@@ -0,0 +1,24 @@
+package org.keycloak.testsuite.auth.page.account;
+
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ContactInfoFields extends Form {
+
+    @FindBy(id = "user.attributes.street")
+    private WebElement streetInput;
+    @FindBy(id = "user.attributes.locality")
+    private WebElement localityInput;
+    @FindBy(id = "user.attributes.region")
+    private WebElement regionInput;
+    @FindBy(id = "user.attributes.postal_code")
+    private WebElement postalCodeInput;
+    @FindBy(id = "user.attributes.country")
+    private WebElement counryInput;
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/PasswordFields.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/PasswordFields.java
new file mode 100644
index 0000000..1d36bf5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/PasswordFields.java
@@ -0,0 +1,38 @@
+package org.keycloak.testsuite.auth.page.account;
+
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class PasswordFields extends Form {
+
+    @FindBy(id = "password")
+    private WebElement passwordInput;
+    @FindBy(id = "password-new")
+    private WebElement newPasswordInput;
+    @FindBy(id = "password-confirm")
+    private WebElement confirmPasswordInput;
+
+    public void setPassword(String password) {
+        setInputValue(passwordInput, password);
+    }
+
+    public void setNewPassword(String newPassword) {
+        setInputValue(newPasswordInput, newPassword);
+    }
+
+    public void setConfirmPassword(String confirmPassword) {
+        setInputValue(confirmPasswordInput, confirmPassword);
+    }
+
+    public void setPasswords(String password, String newPassword, String confirmPassword) {
+        setPassword(password);
+        setNewPassword(newPassword);
+        setConfirmPassword(confirmPassword);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthRealm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthRealm.java
new file mode 100644
index 0000000..e8a435c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthRealm.java
@@ -0,0 +1,58 @@
+package org.keycloak.testsuite.auth.page;
+
+import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
+import java.net.URI;
+import javax.ws.rs.core.UriBuilder;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+
+/**
+ * Keycloak realm.
+ * 
+ * URL: http://localhost:${auth.server.http.port}/auth/realms/{authRealm}
+ * 
+ * @author tkyjovsk
+ */
+public class AuthRealm extends AuthServer implements PageWithLoginUrl {
+
+    public static final String AUTH_REALM = "authRealm";
+
+    public static final String MASTER = "master";
+    public static final String TEST = "test";
+    public static final String DEMO = "demo";
+    public static final String EXAMPLE = "example";
+
+    public static final String ADMIN = "admin";
+    
+    public AuthRealm() {
+        setUriParameter(AUTH_REALM, MASTER);
+    }
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder()
+                .path("realms/{" + AUTH_REALM + "}");
+    }
+
+    public void setAuthRealm(String authRealm) {
+        setUriParameter(AUTH_REALM, authRealm);
+    }
+
+    public void setAuthRealm(AuthRealm authRealm) {
+        setUriParameter(AUTH_REALM, authRealm.getAuthRealm());
+    }
+
+    public String getAuthRealm() {
+        return (String) getUriParameter(AUTH_REALM);
+    }
+
+    /**
+     *
+     * @return OIDC Login URL for authRealm
+     */
+    @Override
+    public URI getOIDCLoginUrl() {
+        return OIDCLoginProtocolService.authUrl(UriBuilder.fromPath(getAuthRoot()))
+                .build(getAuthRealm());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java
new file mode 100644
index 0000000..373c7bb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.auth.page;
+
+import java.net.URI;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.admin.client.Keycloak;
+
+/**
+ * Context path of Keycloak auth server.
+ * 
+ * URL: http://localhost:${auth.server.http.port}/auth
+ * 
+ * @author tkyjovsk
+ */
+public class AuthServer extends AuthServerContextRoot {
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder().path("auth");
+    }
+
+    public String getAuthRoot() {
+        URI uri = buildUri();
+        return uri.getScheme() + "://" + uri.getAuthority() + "/auth";
+    }
+
+    @ArquillianResource
+    protected Keycloak keycloak;
+
+    public Keycloak keycloak() {
+        return keycloak;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServerContextRoot.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServerContextRoot.java
new file mode 100644
index 0000000..6baf3a4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServerContextRoot.java
@@ -0,0 +1,26 @@
+package org.keycloak.testsuite.auth.page;
+
+import java.net.URL;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.arquillian.annotation.AuthServerContext;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ * Context root of the tested Keycloak server.
+ * 
+ * URL: http://localhost:${auth.server.http.port}
+ * 
+ * @author tkyjovsk
+ */
+public class AuthServerContextRoot extends AbstractPageWithInjectedUrl {
+
+    @ArquillianResource
+    @AuthServerContext
+    private URL authServerContextRoot;
+
+    @Override
+    public URL getInjectedUrl() {
+        return authServerContextRoot;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Authenticate.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Authenticate.java
new file mode 100644
index 0000000..97dc1da
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Authenticate.java
@@ -0,0 +1,24 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class Authenticate extends LoginActions {
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder().path("authenticate");
+    }
+
+    @Page
+    private LoginForm login;
+
+    public LoginForm loginForm() {
+        return login;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Login.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Login.java
new file mode 100644
index 0000000..e06c5b9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Login.java
@@ -0,0 +1,72 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.auth.page.login;
+
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementNotPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public abstract class Login extends AuthRealm {
+
+    public static final String PROTOCOL = "protocol";
+    public static final String OIDC = "openid-connect";
+    public static final String SAML = "saml";
+
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder()
+                .path("protocol/{" + PROTOCOL + "}/auth");
+    }
+    
+    public void setProtocol(String protocol) {
+        setUriParameter(PROTOCOL, protocol);
+    }
+    
+    public String getProtocol() {
+        return getUriParameter(PROTOCOL).toString();
+    }
+    
+    @Page
+    private LoginForm form;
+
+    public LoginForm form() {
+        return form;
+    }
+
+    @FindBy(css = "link[href*='login/keycloak/css/login.css']")
+    private WebElement keycloakTheme;
+
+    public void waitForKeycloakThemeNotPresent() {
+        waitGuiForElementNotPresent(keycloakTheme);
+    }
+
+    public void waitForKeycloakThemePresent() {
+        waitGuiForElement(keycloakTheme);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginActions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginActions.java
new file mode 100644
index 0000000..3441677
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginActions.java
@@ -0,0 +1,43 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import javax.ws.rs.core.UriBuilder;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class LoginActions extends AuthRealm {
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder()
+                .path("login-actions");
+    }
+
+    @FindBy(css = "input[type='submit']")
+    private WebElement submitButton;
+
+    @FindBy(css = "div[id='kc-form-options'] span a")
+    private WebElement backToLoginForm;
+
+    @FindBy(css = "span.kc-feedback-text")
+    private WebElement feedbackText;
+    
+    public String getFeedbackText() {
+        waitGuiForElementPresent(feedbackText, "Feedback message should be visible");
+        return feedbackText.getText();
+    }
+    
+    public void backToLoginPage() {
+        backToLoginForm.click();
+    }
+
+    public void submit() {
+        submitButton.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java
new file mode 100644
index 0000000..61075f2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java
@@ -0,0 +1,83 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.admin.Users.getPasswordOf;
+import org.keycloak.testsuite.auth.page.account.AccountFields;
+import org.keycloak.testsuite.auth.page.account.PasswordFields;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElementNotPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class LoginForm extends Form {
+
+    @Page
+    private AccountFields accountFields;
+    @Page
+    private PasswordFields passwordFields;
+
+    @FindBy(name = "login")
+    private WebElement loginButton;
+//    @FindBy(name = "cancel")
+//    private WebElement cancelButton;
+
+    @FindBy(linkText = "Register")
+    private WebElement registerLink;
+    @FindBy(linkText = "Forgot Password?")
+    private WebElement forgottenPassword;
+
+    public void setUsername(String username) {
+        accountFields.setUsername(username);
+    }
+
+    public void setPassword(String password) {
+        passwordFields.setPassword(password);
+    }
+
+    public void login(UserRepresentation user) {
+        login(user.getUsername(), getPasswordOf(user));
+    }
+
+    public void login(String username, String password) {
+        setUsername(username);
+        setPassword(password);
+        login();
+    }
+
+    public void register() {
+        waitForUsernameInputPresent();
+        waitAjaxForElement(registerLink);
+        registerLink.click();
+    }
+
+    public void login() {
+        waitAjaxForElement(loginButton);
+        loginButton.click();
+    }
+    
+    public void forgotPassword() {
+        waitAjaxForElement(forgottenPassword);
+        forgottenPassword.click();
+    }
+
+//    @Override
+//    public void cancel() {
+//        waitAjaxForElement(cancelButton);
+//        cancelButton.click();
+//    }
+    
+    public void waitForUsernameInputPresent() {
+        accountFields.waitForUsernameInputPresent();
+    }
+
+    public void waitForRegisterLinkNotPresent() {
+        waitAjaxForElementNotPresent(registerLink);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/OIDCLogin.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/OIDCLogin.java
new file mode 100644
index 0000000..d002da8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/OIDCLogin.java
@@ -0,0 +1,13 @@
+package org.keycloak.testsuite.auth.page.login;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class OIDCLogin extends Login {
+
+    public OIDCLogin() {
+        setProtocol(OIDC);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/PageWithLoginUrl.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/PageWithLoginUrl.java
new file mode 100644
index 0000000..53bef17
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/PageWithLoginUrl.java
@@ -0,0 +1,15 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import java.net.URI;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * Used by util class LoginAssert. Implementing classes: AuthRealm, AdminConsole.
+ * @author tkyjovsk
+ */
+public interface PageWithLoginUrl {
+
+    WebDriver getDriver();
+    URI getOIDCLoginUrl();
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Registration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Registration.java
new file mode 100644
index 0000000..da70da4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Registration.java
@@ -0,0 +1,77 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.auth.page.login;
+
+import org.keycloak.testsuite.auth.page.account.AccountFields;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent;
+import static org.keycloak.testsuite.admin.Users.getPasswordOf;
+import org.keycloak.testsuite.auth.page.account.ContactInfoFields;
+import org.keycloak.testsuite.auth.page.account.PasswordFields;
+
+/**
+ *
+ * @author Filip Kiss
+ */
+public class Registration extends LoginActions {
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder()
+                .path("registration");
+    }
+
+    @Page
+    private AccountFields accountFields;
+
+    @Page
+    private PasswordFields passwordFields;
+
+    @Page
+    private ContactInfoFields contactInfoFields;
+
+    public void register(UserRepresentation user) {
+        setValues(user);
+        submit();
+    }
+    
+    public void setValues(UserRepresentation user) {
+        setValues(user, getPasswordOf(user));
+    }
+
+    public void setValues(UserRepresentation user, String confirmPassword) {
+        accountFields.setValues(user);
+        passwordFields.setPassword(getPasswordOf(user));
+        passwordFields.setConfirmPassword(confirmPassword);
+    }
+
+    public void waitForUsernameInputPresent() {
+        accountFields.waitForUsernameInputPresent();
+    }
+
+    public void waitForUsernameInputNotPresent() {
+        accountFields.waitForUsernameInputNotPresent();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdateAccount.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdateAccount.java
new file mode 100644
index 0000000..b1e5c25
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdateAccount.java
@@ -0,0 +1,27 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import org.keycloak.testsuite.auth.page.account.AccountFields;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UpdateAccount extends Authenticate {
+
+    @Page
+    private AccountFields accountFields;
+
+    public void updateAccount(UserRepresentation user) {
+        updateAccount(user.getEmail(), user.getFirstName(), user.getLastName());
+    }
+    
+    public void updateAccount(String email, String firstName, String lastName) {
+        accountFields.setEmail(email);
+        accountFields.setFirstName(firstName);
+        accountFields.setLastName(lastName);
+        submit();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdatePassword.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdatePassword.java
new file mode 100644
index 0000000..b0cc4c3
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdatePassword.java
@@ -0,0 +1,21 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import org.keycloak.testsuite.auth.page.account.PasswordFields;
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UpdatePassword extends Authenticate {
+
+    @Page
+    private PasswordFields passwordFields;
+
+    public void updatePasswords(String newPassword, String confirmPassword) {
+        passwordFields.setNewPassword(newPassword);
+        passwordFields.setConfirmPassword(confirmPassword);
+        submit();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java
new file mode 100644
index 0000000..575ce7b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java
@@ -0,0 +1,9 @@
+package org.keycloak.testsuite.auth.page.login;
+
+/**
+ *
+ * @author vramik
+ */
+public class VerifyEmail extends Authenticate {
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsole.java
new file mode 100644
index 0000000..47bff5d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsole.java
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.page;
+
+import java.net.URI;
+import org.keycloak.testsuite.auth.page.AuthServer;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
+import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
+import org.keycloak.testsuite.console.page.fragment.Menu;
+import org.keycloak.testsuite.console.page.fragment.ModalDialog;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author Petr Mensik
+ */
+public class AdminConsole extends AuthServer implements PageWithLoginUrl {
+    
+    public static final String ADMIN_REALM = "adminRealm";
+
+    public AdminConsole() {
+        setUriParameter(ADMIN_REALM, MASTER);
+    }
+
+    public AdminConsole setAdminRealm(String adminRealm) {
+        setUriParameter(ADMIN_REALM, adminRealm);
+        return this;
+    }
+
+    public String getAdminRealm() {
+        return getUriParameter(ADMIN_REALM).toString();
+    }
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder().path("admin/{" + ADMIN_REALM + "}/console");
+    }
+
+    @Page
+    private Menu menu;
+    
+    @FindBy(xpath = "//div[@class='modal-dialog']")
+    protected ModalDialog modalDialog;
+
+    /**
+     *
+     * @return OIDC Login URL for adminRealm parameter
+     */
+    @Override
+    public URI getOIDCLoginUrl() {
+        return OIDCLoginProtocolService.authUrl(UriBuilder.fromPath(getAuthRoot()))
+                .build(getAdminRealm());
+    }
+
+    @FindBy(css = ".btn-danger")
+    protected WebElement dangerButton;
+
+    //@FindByJQuery(".btn-primary:visible")
+    @FindBy(css = ".btn-primary")
+    protected WebElement primaryButton;
+
+    @FindBy(css = "navbar-brand")
+    protected WebElement brandLink;
+    
+    public void logOut() {
+        menu.logOut();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleCreate.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleCreate.java
new file mode 100644
index 0000000..35be14d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleCreate.java
@@ -0,0 +1,47 @@
+package org.keycloak.testsuite.console.page;
+
+import javax.ws.rs.core.UriBuilder;
+import static org.keycloak.testsuite.console.page.AdminConsoleRealm.CONSOLE_REALM;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminConsoleCreate extends AdminConsole {
+
+    public static final String ENTITY = "entity";
+
+    public AdminConsoleCreate() {
+        setUriParameter(CONSOLE_REALM, TEST);
+    }
+    
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder().path("/");
+    }
+    
+    @Override
+    public String getUriFragment() {
+        return "/create/{" + ENTITY + "}/{" + CONSOLE_REALM + "}";
+    }
+
+    public AdminConsoleCreate setEntity(String entity) {
+        setUriParameter(ENTITY, entity);
+        return this;
+    }
+
+    public String getEntity() {
+        return getUriParameter(ENTITY).toString();
+    }
+
+    public AdminConsoleCreate setConsoleRealm(String consoleRealm) {
+        setUriParameter(CONSOLE_REALM, consoleRealm);
+        return this;
+    }
+
+    public String getConsoleRealm() {
+        return getUriParameter(CONSOLE_REALM).toString();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java
new file mode 100644
index 0000000..4fd57ba
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java
@@ -0,0 +1,121 @@
+package org.keycloak.testsuite.console.page;
+
+import org.keycloak.admin.client.resource.RealmResource;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+
+import org.keycloak.testsuite.util.WaitUtils;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
+
+    public static final String CONSOLE_REALM = "consoleRealm";
+
+    public AdminConsoleRealm() {
+        setUriParameter(CONSOLE_REALM, TEST);
+    }
+
+    public AdminConsoleRealm setConsoleRealm(String realm) {
+        setUriParameter(CONSOLE_REALM, realm);
+        return this;
+    }
+
+    public String getConsoleRealm() {
+        return getUriParameter(CONSOLE_REALM).toString();
+    }
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/{" + CONSOLE_REALM + "}";
+    }
+
+    @FindBy(xpath = "//div[./h2[text()='Configure']]")
+    private ConfigureMenu configureMenu;
+
+    public ConfigureMenu configure() {
+        waitGuiForElement(By.xpath("//div[./h2[text()='Configure']]"));
+        return configureMenu;
+    }
+
+    public RealmResource realmResource() {
+        return realmsResource().realm(getConsoleRealm());
+    }
+
+    public class ConfigureMenu {
+
+        @FindBy(partialLinkText = "Realm Settings")
+        private WebElement realmSettingsLink;
+        @FindBy(partialLinkText = "Clients")
+        private WebElement clientsLink;
+        @FindBy(partialLinkText = "Roles")
+        private WebElement rolesLink;
+        @FindBy(partialLinkText = "Identity Providers")
+        private WebElement identityProvidersLink;
+        @FindBy(partialLinkText = "User Feferation")
+        private WebElement userFederationLink;
+        @FindBy(partialLinkText = "Authentication")
+        private WebElement authenticationLink;
+
+        public void realmSettings() {
+            realmSettingsLink.click();
+        }
+
+        public void clients() {
+            clientsLink.click();
+        }
+
+        public void roles() {
+            rolesLink.click();
+        }
+
+        public void identityProviders() {
+            identityProvidersLink.click();
+        }
+
+        public void userFederation() {
+            userFederationLink.click();
+        }
+
+        public void authentication() {
+            authenticationLink.click();
+        }
+
+    }
+
+    @FindBy(xpath = "//div[./h2[text()='Manage']]")
+    protected ManageMenu manageMenu;
+
+    public ManageMenu manage() {
+        WaitUtils.waitGuiForElement(By.xpath("//div[./h2[text()='Manage']]"));
+        return manageMenu;
+    }
+
+    public class ManageMenu {
+
+        @FindBy(partialLinkText = "Users")
+        private WebElement usersLink;
+        @FindBy(partialLinkText = "Sessions")
+        private WebElement sessionsLink;
+        @FindBy(partialLinkText = "Events")
+        private WebElement eventsLink;
+
+        public void users() {
+            usersLink.click();
+        }
+
+        public void sessions() {
+            sessionsLink.click();
+        }
+
+        public void events() {
+            eventsLink.click();
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java
new file mode 100644
index 0000000..bb001ea
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java
@@ -0,0 +1,49 @@
+package org.keycloak.testsuite.console.page;
+
+import java.util.List;
+import javax.ws.rs.core.UriBuilder;
+import org.keycloak.admin.client.resource.RealmsResource;
+import org.keycloak.testsuite.console.page.fragment.RealmSelector;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminConsoleRealmsRoot extends AdminConsole {
+
+    @FindBy(xpath = "//tr[@data-ng-repeat='r in realms']//a[contains(@class,'ng-binding')]")
+    private List<WebElement> realmLinks;
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder().path("/");
+    }
+
+    @Override
+    public String getUriFragment() {
+        return "/realms";
+    }
+
+    public void clickRealm(String realm) {
+        boolean linkFound = false;
+        for (WebElement realmLink : realmLinks) {
+            if (realmLink.getText().equals(realm)) {
+                linkFound = true;
+                realmLink.click();
+            }
+        }
+        if (!linkFound) {
+            throw new IllegalStateException("A link for realm '" + realm + "' not found on the Realms page.");
+        }
+    }
+
+    @FindBy(css = "realm-selector")
+    protected RealmSelector realmSelector;
+
+    public RealmsResource realmsResource() {
+        return keycloak.realms();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Authentication.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Authentication.java
new file mode 100644
index 0000000..5cd74bf
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Authentication.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class Authentication extends AdminConsoleRealm {
+
+    @FindBy(xpath = "//h1[text()='Authentication']/..")
+    private AuthenticationTabs authenticationTabs;
+
+    public AuthenticationTabs tabs() {
+        return authenticationTabs;
+    }
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/authentication";
+    }
+
+    public class AuthenticationTabs {
+        @FindBy(linkText = "Flows")
+        private WebElement flowsTab;
+        @FindBy(linkText = "Required Actions")
+        private WebElement requiredActionsTab;
+        @FindBy(linkText = "Password Policy")
+        private WebElement passwordPolicyTab;
+        @FindBy(linkText = "Bindings")
+        private WebElement binding;
+        @FindBy(linkText = "OTP Policy")
+        private WebElement otpPolicy;
+
+        public void flows() {
+            flowsTab.click();
+        }
+
+        public void requiredActions() {
+            requiredActionsTab.click();
+        }
+
+        public void passwordPolicy() {
+            passwordPolicyTab.click();
+        }
+
+        public void binding() {
+            binding.click();
+        }
+
+        public void otpPolicy() {
+            otpPolicy.click();
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Bindings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Bindings.java
new file mode 100644
index 0000000..6e8d4a4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Bindings.java
@@ -0,0 +1,147 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * Created by mhajas on 8/21/15.
+ */
+public class Bindings extends Authentication{
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/flow-binding";
+    }
+
+    @FindBy(id = "browser")
+    private Select BrowserFlowSelect;
+
+    public void changeBrowserFlowSelect(BrowserFlowSelectValues value) {
+        BrowserFlowSelect.selectByVisibleText(value.getName());
+    }
+
+    @FindBy(id = "registration")
+    private Select RegistrationFlowSelect;
+
+    public void changeRegistrationFlowSelect(RegistrationFlowSelectValues value) {
+        RegistrationFlowSelect.selectByVisibleText(value.getName());
+    }
+
+    @FindBy(id = "grant")
+    private Select DirectGrantFlowSelect;
+
+    public void changeDirectGrantFlowSelect(DirectGrantFlowSelectValues value) {
+        DirectGrantFlowSelect.selectByVisibleText(value.getName());
+    }
+
+    @FindBy(id = "resetCredentials")
+    private Select ResetCredentialsSelect;
+
+    public void changeResetCredentialsSelect(ResetCredentialsSelectValues value) {
+        ResetCredentialsSelect.selectByVisibleText(value.getName());
+    }
+
+    @FindBy(id = "clientAuthentication")
+    private Select ClientAuthenticationSelect;
+
+    public void changeClientAuthenticationSelect(ClientAuthenticationSelectValues value) {
+        ClientAuthenticationSelect.selectByVisibleText(value.getName());
+    }
+
+    @FindBy(xpath = "//button[text()='Save']")
+    private WebElement saveButton;
+
+    public void clickSave() {
+        saveButton.click();
+    }
+
+    @FindBy(xpath = "//button[text()='Cancel']")
+    private WebElement cancelButton;
+
+    public void clickCancel() {
+        cancelButton.click();
+    }
+
+    public enum BrowserFlowSelectValues {
+
+        DIRECT_GRANT("direct grant"), REGISTRATION("registration"), BROWSER("browser"),
+        RESET_CREDENTIALS("reset credentials");
+
+        private String name;
+
+        private BrowserFlowSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    public enum RegistrationFlowSelectValues {
+
+        DIRECT_GRANT("direct grant"), REGISTRATION("registration"), BROWSER("browser"),
+        RESET_CREDENTIALS("reset credentials");
+
+        private String name;
+
+        private RegistrationFlowSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    public enum DirectGrantFlowSelectValues {
+
+        DIRECT_GRANT("direct grant"), REGISTRATION("registration"), BROWSER("browser"),
+        RESET_CREDENTIALS("reset credentials");
+
+        private String name;
+
+        private DirectGrantFlowSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    public enum ResetCredentialsSelectValues {
+
+        DIRECT_GRANT("direct grant"), REGISTRATION("registration"), BROWSER("browser"),
+        RESET_CREDENTIALS("reset credentials"), NOTHING("");
+
+        private String name;
+
+        private ResetCredentialsSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    public enum ClientAuthenticationSelectValues {
+
+        CLIENTS("clients");
+
+        private String name;
+
+        private ClientAuthenticationSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Flows.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Flows.java
new file mode 100644
index 0000000..1994064
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Flows.java
@@ -0,0 +1,212 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class Flows extends Authentication {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/flows";
+    }
+
+    @FindBy(tagName = "select")
+    private Select flowSelect;
+
+    public void changeFlowSelect(FlowSelectValues value) {
+        flowSelect.selectByVisibleText(value.getName());
+    }
+
+    public enum FlowSelectValues {
+
+        DIRECT_GRANT("Direct grant"), REGISTRATION("Registration"), BROWSER("Browser"),
+        RESET_CREDENTIALS("Reset credentials"), CLIENTS("Clients");
+
+        private String name;
+
+        private FlowSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    @FindBy(linkText = "New")
+    private WebElement newButton;
+
+    @FindBy(linkText = "Copy")
+    private WebElement copyButton;
+
+    public void clickNew() {
+        newButton.click();
+    }
+
+    public void clickCopy() {
+        copyButton.click();
+    }
+
+    // Direct grant
+    public void setPasswordRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Password')]]/../td[2]//input[@type='radio']")).click();
+    }
+
+    public void setPasswordDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Password')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setOTPRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'O T P')]]/../td[2]//input[@type='radio']")).click();
+    }
+
+    public void setOTPOptional() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'O T P')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setOTPDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'O T P')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    // Registration
+    public void setRegistrationFormRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Registration form')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setRegistrationFormDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Registration form')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setRegistrationUserCreationRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Registration  User  Creation')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setRegistrationUserCreationDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Registration  User  Creation')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setProfileValidationRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Profile  Validation')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setProfileValidationDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Profile  Validation')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setPasswordValidationRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Password  Validation')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setPasswordValidationDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Password  Validation')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setRecaptchaRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Recaptcha')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setRecaptchaDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Recaptcha')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    // Browser
+    public void setCookieAlternative() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Cookie')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setCookieDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Cookie')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setKerberosAlternative() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Kerberos')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setKerberosRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Kerberos')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setKerberosDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Kerberos')]]/../td[5]//input[@type='radio']")).click();
+    }
+
+    public void setFormsAlternative() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Forms')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setFormsRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Forms')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setFormsDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Forms')]]/../td[5]//input[@type='radio']")).click();
+    }
+
+    public void setOTPFormRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' O T P  Form')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setOTPFormOptional() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' O T P  Form')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setOTPFormDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' O T P  Form')]]/../td[5]//input[@type='radio']")).click();
+    }
+
+    // Reset credentials
+    public void setResetPasswordRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset  Password')]]/../td[2]//input[@type='radio']")).click();
+    }
+
+    public void setResetPasswordOptional() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset  Password')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setResetPasswordDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset  Password')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setResetOTPRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset  O T P')]]/../td[2]//input[@type='radio']")).click();
+    }
+
+    public void setResetOTPOptional() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset  O T P')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setResetOTPDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset  O T P')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    // Clients
+    public void setClientIdAndSecretRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Client  Id and  Secret')]]/../td[2]//input[@type='radio']")).click();
+    }
+
+    public void setClientIdAndSecretAlternative() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Client  Id and  Secret')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setClientIdAndSecretDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Client  Id and  Secret')]]/../td[4]//input[@type='radio']")).click();
+    }
+
+    public void setSignedJwtRequired() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' Signed  Jwt')]]/../td[2]//input[@type='radio']")).click();
+    }
+
+    public void setSignedJwtAlternative() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' Signed  Jwt')]]/../td[3]//input[@type='radio']")).click();
+    }
+
+    public void setSignedJwtDisabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' Signed  Jwt')]]/../td[4]//input[@type='radio']")).click();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/OTPPolicy.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/OTPPolicy.java
new file mode 100644
index 0000000..34e8a09
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/OTPPolicy.java
@@ -0,0 +1,85 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * Created by mhajas on 8/21/15.
+ */
+public class OTPPolicy extends Authentication {
+
+    @FindBy(linkText = "Save")
+    private WebElement saveButton;
+
+    public void clickSave() {
+        saveButton.click();
+    }
+
+    @FindBy(linkText = "Cancel")
+    private WebElement cancelButton;
+
+    public void clickCancel() {
+        cancelButton.click();
+    }
+
+    @FindBy(id = "lookAhead")
+    private WebElement lookAheadInput;
+
+    public void setLookAheadInputValue(String value) {
+        Form.setInputValue(lookAheadInput, value);
+    }
+
+    @FindBy(id = "counter")
+    private WebElement initialCounterInput;
+
+    public void setInitialcounterInputValue(String value) {
+        Form.setInputValue(initialCounterInput, value);
+    }
+
+    public enum OTPTypeSelectValues {
+
+        TIME_BASED("time Based"), COUNTER_BASED("Counter Based");
+
+        private String name;
+
+        private OTPTypeSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    public enum OTPHashAlgorithmSelectValues {
+
+        SHA1("SHA1"), SHA256("SHA256"), SHA512("SHA512");
+
+        private String name;
+
+        private OTPHashAlgorithmSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    public enum NumberOfDigitsSelectValues {
+
+        NUMBER6("6"), NUMBER8("8");
+
+        private String name;
+
+        private NumberOfDigitsSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java
new file mode 100644
index 0000000..b2b08b5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java
@@ -0,0 +1,100 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import java.util.List;
+
+import org.jboss.arquillian.graphene.findby.ByJQuery;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author Petr Mensik
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class PasswordPolicy extends Authentication {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/password-policy";
+    }
+
+    @FindBy(tagName = "select")
+    private Select addPolicySelect;
+    
+    @FindBy(tagName = "select")
+    private WebElement addPolicySelectElement;
+
+    @FindBy(css = "tr.ng-scope")
+    private List<WebElement> allRows;
+
+    public void addPolicy(PasswordPolicy.Type policy, String value) {
+        waitGuiForElement(addPolicySelectElement);
+        addPolicySelect.selectByVisibleText(policy.getName());
+        setPolicyValue(policy, value);
+        primaryButton.click();
+    }
+
+
+    public void addPolicy(PasswordPolicy.Type policy, int value) {
+        addPolicy(policy, String.valueOf(value));
+    }
+
+    public void addPolicy(PasswordPolicy.Type policy) {
+        addPolicySelect.selectByVisibleText(policy.getName());
+        primaryButton.click();
+    }
+
+    public void removePolicy(PasswordPolicy.Type policy) {
+        int policyInputLocation = findPolicy(policy);
+        allRows.get(policyInputLocation).findElements(By.tagName("button")).get(0).click();
+        primaryButton.click();
+    }
+
+    public void editPolicy(PasswordPolicy.Type policy, int value) {
+        editPolicy(policy, String.valueOf(value));
+    }
+
+    public void editPolicy(PasswordPolicy.Type policy, String value) {
+        setPolicyValue(policy, value);
+        primaryButton.click();
+    }
+
+    private void setPolicyValue(PasswordPolicy.Type policy, String value) {
+        int policyInputLocation = findPolicy(policy);
+        WebElement input = allRows.get(policyInputLocation).findElement(By.tagName("input"));
+        input.clear();
+        input.sendKeys(value);
+    }
+
+    private int findPolicy(PasswordPolicy.Type policy) {
+        for (int i = 0; i < allRows.size(); i++) {
+            String policyName = allRows.get(i).findElement(ByJQuery.selector("td:eq(0)")).getText();
+            if (policyName.equals(policy.getName())) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    public enum Type {
+
+        HASH_ITERATIONS("Hash Iterations"), LENGTH("Length"), DIGITS("Digits"), LOWER_CASE("Lower Case"),
+        UPPER_CASE("Upper Case"), SPECIAL_CHARS("Special Chars"), NOT_USERNAME("Not Username"),
+        REGEX_PATTERN("Regex Pattern"), PASSWORD_HISTORY("Password History"),
+        FORCE_EXPIRED_PASSWORD_CHANGE("Force Expired Password Change");
+
+        private String name;
+
+        private Type(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/RequiredActions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/RequiredActions.java
new file mode 100644
index 0000000..5da1cda
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/RequiredActions.java
@@ -0,0 +1,55 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.openqa.selenium.By;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class RequiredActions extends Authentication {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/required-actions";
+    }
+
+    public void clickTermsAndConditionEnabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Terms and Conditions']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+    }
+
+    public void clickTermsAndConditionDefaultAction() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Terms and Conditions']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+    }
+
+    public void clickVerifyEmailEnabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Verify Email']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+    }
+
+    public void clickVerifyEmailDefaultAction() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Verify Email']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+    }
+
+    public void clickUpdatePasswordEnabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Update Password']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+    }
+
+    public void clickUpdatePasswordDefaultAction() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Update Password']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+    }
+
+    public void clickConfigureTotpEnabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Configure Totp']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+    }
+
+    public void clickConfigureTotpDefaultAction() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Configure Totp']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+    }
+
+    public void clickUpdateProfileEnabled() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Update Profile']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+    }
+
+    public void clickUpdateProfileDefaultAction() {
+        driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Update Profile']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java
new file mode 100644
index 0000000..783cd0b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java
@@ -0,0 +1,107 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.testsuite.console.page.fragment.Breadcrumb;
+import static org.keycloak.testsuite.console.page.fragment.Breadcrumb.BREADCRUMB_XPATH;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Client extends Clients {
+
+    public static final String ID = "id"; // TODO client.id vs client.clientId
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/{" + ID + "}";
+    }
+
+    public final void setId(String id) {
+        setUriParameter(ID, id);
+    }
+
+    public String getId() {
+        return getUriParameter(ID).toString();
+    }
+
+    @FindBy(xpath = BREADCRUMB_XPATH)
+    private Breadcrumb breadcrumb;
+
+    public Breadcrumb breadcrumb() {
+        return breadcrumb;
+    }
+
+    public void backToClientsViaBreadcrumb() {
+        breadcrumb.clickItemOneLevelUp();
+    }
+
+    @FindBy(id = "removeClient")
+    private WebElement deleteIcon;
+    
+    public void delete() {
+        deleteIcon.click();
+        modalDialog.confirmDeletion();
+    }
+
+    @FindBy(xpath = "//div[@data-ng-controller='ClientTabCtrl']/ul")
+    protected ClientTabs clientTabs;
+
+    public ClientTabs tabs() {
+        return clientTabs;
+    }
+
+    public class ClientTabs {
+
+        @FindBy(linkText = "Settings")
+        private WebElement settingsLink;
+        @FindBy(linkText = "Roles")
+        private WebElement rolesLink;
+        @FindBy(linkText = "Mappers")
+        private WebElement mappersLink;
+        @FindBy(linkText = "Scope")
+        private WebElement scopeLink;
+        @FindBy(linkText = "Revocation")
+        private WebElement revocationLink;
+        @FindBy(linkText = "Sessions")
+        private WebElement sessionsLink;
+        @FindBy(linkText = "Installation")
+        private WebElement installationLink;
+
+        public void settings() {
+            settingsLink.click();
+        }
+
+        public void roles() {
+            rolesLink.click();
+        }
+
+        public void mappers() {
+            mappersLink.click();
+        }
+
+        public void scope() {
+            scopeLink.click();
+        }
+
+        public void revocation() {
+            revocationLink.click();
+        }
+
+        public void sessions() {
+            sessionsLink.click();
+        }
+
+        public void installation() {
+            installationLink.click();
+        }
+
+    }
+
+    public ClientResource clientResource() {
+        return clientsResource().get(getId());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientClustering.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientClustering.java
new file mode 100644
index 0000000..cdc8d6b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientClustering.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientClustering extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/clustering";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientCredentials.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientCredentials.java
new file mode 100644
index 0000000..08a3523
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientCredentials.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientCredentials extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/credentials";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientInstallation.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientInstallation.java
new file mode 100644
index 0000000..65c1c6c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientInstallation.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientInstallation extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/installation";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientMappers.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientMappers.java
new file mode 100644
index 0000000..d56dca5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientMappers.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientMappers extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/mappers";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRevocation.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRevocation.java
new file mode 100644
index 0000000..fb161a8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRevocation.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientRevocation extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/revocation";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java
new file mode 100644
index 0000000..d0a0b0d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java
@@ -0,0 +1,36 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.keycloak.testsuite.console.page.roles.*;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientRole extends ClientRoles {
+
+    public static final String ROLE_ID = "roleId";
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/{" + ROLE_ID + "}";
+    }
+
+    public void setRoleId(String id) {
+        setUriParameter(ROLE_ID, id);
+    }
+
+    public String getRoleId() {
+        return getUriParameter(ROLE_ID).toString();
+    }
+
+    private RoleForm form;
+
+    public RoleForm form() {
+        return form;
+    }
+
+    public void backToClientRolesViaBreadcrumb() {
+        breadcrumb().clickItemOneLevelUp();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRoles.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRoles.java
new file mode 100644
index 0000000..a8ee969
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRoles.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.keycloak.admin.client.resource.RolesResource;
+import org.keycloak.testsuite.console.page.roles.RolesTable;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientRoles extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/roles";
+    }
+    
+    @FindBy(css = "table[class*='table']")
+    private RolesTable table;
+
+    public RolesTable roles() {
+        return table;
+    }
+    
+    public RolesResource rolesResource() {
+        return clientResource().roles();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
new file mode 100644
index 0000000..6f9cccd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
@@ -0,0 +1,138 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.page.clients;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+
+import static org.openqa.selenium.By.linkText;
+import static org.openqa.selenium.By.tagName;
+
+/**
+ *
+ * @author Filip Kisss
+ */
+public class Clients extends AdminConsoleRealm {
+
+    public static final String CREATE = "Create";
+    public static final String IMPORT = "Import";
+
+    public static final String EDIT = "Edit";
+    public static final String DELETE = "Delete";
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/clients";
+    }
+
+    @FindBy(tagName = "table")
+    private ClientsTable clientsTable;
+
+    public ClientsTable table() {
+        return clientsTable;
+    }
+
+    public class ClientsTable extends DataTable {
+
+        public List<ClientRepresentation> searchClients(String searchPattern) {
+            search(searchPattern);
+            return getClientsFromRows();
+        }
+
+        public void createClient() {
+            waitAjaxForBody();
+            clickHeaderLink(CREATE);
+        }
+
+        public void importClient() {
+            waitAjaxForBody();
+            clickHeaderLink(IMPORT);
+        }
+
+        public void clickClient(ClientRepresentation client) {
+            waitAjaxForBody();
+            clickClient(client.getClientId());
+        }
+
+        public void clickClient(String clientId) {
+            waitAjaxForBody();
+            body().findElement(linkText(clientId)).click();
+        }
+
+        public void editClient(String clientId) {
+            waitAjaxForBody();
+            clickRowActionButton(getRowByLinkText(clientId), EDIT);
+        }
+
+        public void deleteClient(String clientId) {
+            waitAjaxForBody();
+            clickRowActionButton(getRowByLinkText(clientId), DELETE);
+        }
+
+        public ClientRepresentation findClient(String clientId) {
+            List<ClientRepresentation> clients = searchClients(clientId);
+            if (clients.isEmpty()) {
+                return null;
+            } else {
+                assert 1 == clients.size();
+                return clients.get(0);
+            }
+        }
+
+        public List<ClientRepresentation> getClientsFromRows() {
+            List<ClientRepresentation> rows = new ArrayList<>();
+            for (WebElement row : rows()) {
+                ClientRepresentation client = getClientFromRow(row);
+                if (client != null) {
+                    rows.add(client);
+                }
+            }
+            return rows;
+        }
+
+        public ClientRepresentation getClientFromRow(WebElement row) {
+            ClientRepresentation client = null;
+            if (row.isDisplayed()) {
+                client = new ClientRepresentation();
+                List<WebElement> tds = row.findElements(tagName("td"));
+                client.setClientId(tds.get(0).getText());
+                List<String> redirectUris = new ArrayList<>();
+                redirectUris.add(tds.get(2).getText()); // FIXME there can be more than 1 redirect uri
+                client.setRedirectUris(redirectUris);
+            }
+            return client;
+        }
+    }
+
+    public void deleteClient(String clientId) {
+        clientsTable.searchClients(clientId);
+        clientsTable.deleteClient(clientId);
+    }
+
+    public ClientsResource clientsResource() {
+        return realmResource().clients();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientScopeMappings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientScopeMappings.java
new file mode 100644
index 0000000..32107fd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientScopeMappings.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientScopeMappings extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/scope-mappings";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSessions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSessions.java
new file mode 100644
index 0000000..eae5013
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSessions.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientSessions extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/sessions";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettings.java
new file mode 100644
index 0000000..8fe1c2c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettings.java
@@ -0,0 +1,18 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientSettings extends Client {
+
+    @Page
+    private ClientSettingsForm form;
+
+    public ClientSettingsForm form() {
+        return form;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettingsForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettingsForm.java
new file mode 100644
index 0000000..41cdf71
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettingsForm.java
@@ -0,0 +1,91 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.auth.page.login.Login.OIDC;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientSettingsForm extends CreateClientForm {
+
+    @FindBy(id = "baseUrl")
+    private WebElement baseUrlInput;
+    @FindBy(id = "adminUrl")
+    private WebElement adminUrlInput;
+
+    @FindBy(id = "newWebOrigin")
+    private WebElement newWebOriginInput;
+    @FindBy(xpath = ".//input[ng-model='client.webOrigins[i]']")
+    private List<WebElement> webOriginInputs;
+    @FindBy(xpath = ".//i[contains(@data-ng-click, 'deleteWebOrigin')]")
+    private List<WebElement> deleteWebOriginIcons;
+
+    public void setBaseUrl(String baseUrl) {
+        setInputValue(baseUrlInput, baseUrl);
+    }
+
+    public String getBaseUrl() {
+        return getInputValue(baseUrlInput);
+    }
+
+    public void setAdminUrl(String adminUrl) {
+        setInputValue(adminUrlInput, adminUrl);
+    }
+
+    public String getAdminUrl() {
+        return getInputValue(adminUrlInput);
+    }
+
+    public void addWebOrigin(String redirectUri) {
+        newWebOriginInput.sendKeys(redirectUri);
+    }
+
+    public List<String> getWebOrigins() {
+        List<String> values = new ArrayList<>();
+        for (WebElement input : webOriginInputs) {
+            values.add(getInputValue(input));
+        }
+        return values;
+    }
+
+    public void setWebOrigins(List<String> webOrigins) {
+        while (!deleteWebOriginIcons.isEmpty()) {
+            deleteWebOriginIcons.get(0).click();
+            pause(100);
+        }
+        if (webOrigins != null) {
+            for (String redirectUri : webOrigins) {
+                addWebOrigin(redirectUri);
+                pause(100);
+            }
+        }
+    }
+
+    @Override
+    public void setValues(ClientRepresentation client) {
+        super.setValues(client);
+        setBaseUrl(client.getBaseUrl());
+        if (OIDC.equals(client.getProtocol())) {
+            setAdminUrl(client.getAdminUrl());
+            setWebOrigins(client.getWebOrigins());
+        }
+    }
+
+    @Override
+    public ClientRepresentation getValues() {
+        ClientRepresentation values = super.getValues();
+        values.setBaseUrl(getBaseUrl());
+        if (OIDC.equals(values.getProtocol())) {
+            values.setAdminUrl(getAdminUrl());
+            values.setWebOrigins(getWebOrigins());
+        }
+        return values;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClient.java
new file mode 100644
index 0000000..87568c9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClient.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.AdminConsoleCreate;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateClient extends AdminConsoleCreate {
+
+    public CreateClient() {
+        setEntity("client");
+    }
+    
+    @Page
+    private CreateClientForm form;
+    
+    public CreateClientForm form() {
+        return form;
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
new file mode 100644
index 0000000..87eadb5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
@@ -0,0 +1,230 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.auth.page.login.OIDCLogin.OIDC;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.page.Form.getInputValue;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.keycloak.testsuite.util.Timer;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateClientForm extends Form {
+
+    @FindBy(id = "clientId")
+    private WebElement clientIdInput;
+
+    @FindBy(id = "name")
+    private WebElement nameInput;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='enabled']]")
+    private OnOffSwitch enabledSwitch;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='consentRequired']]")
+    private OnOffSwitch consentRequiredSwitch;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='directGrantsOnly']]")
+    private OnOffSwitch directGrantsOnlySwitch;
+
+    @FindBy(id = "protocol")
+    private Select protocolSelect;
+    @FindBy(id = "protocol")
+    private WebElement protocolSelectElement;
+
+    @FindBy
+    private SAMLClientSettingsForm samlForm;
+
+    public SAMLClientSettingsForm samlForm() {
+        return samlForm;
+    }
+
+    @FindBy(id = "accessType")
+    private Select accessTypeSelect;
+    @FindBy(id = "accessType")
+    private WebElement accessTypeSelectElement;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='serviceAccountsEnabled']]")
+    private OnOffSwitch serviceAccountsEnabledSwitch;
+
+    @FindBy(id = "newRedirectUri")
+    private WebElement newRedirectUriInput;
+    @FindBy(xpath = ".//input[@ng-model='client.redirectUris[i]']")
+    private List<WebElement> redirectUriInputs;
+    @FindBy(xpath = ".//i[contains(@data-ng-click, 'deleteRedirectUri')]")
+    private List<WebElement> deleteRedirectUriIcons;
+
+    public void setValues(ClientRepresentation client) {
+        waitAjaxForElement(clientIdInput);
+
+        setClientId(client.getClientId());
+        setName(client.getName());
+        setEnabled(client.isEnabled());
+        setConsentRequired(client.isConsentRequired());
+        setDirectGrantsOnly(client.isDirectGrantsOnly());
+        setProtocol(client.getProtocol());
+        if (OIDC.equals(client.getProtocol())) {
+            setAccessType(client);
+            if (!client.isBearerOnly()) {
+                if (!client.isPublicClient()) {
+                    setServiceAccountsEnabled(client.isServiceAccountsEnabled());
+                }
+                setRedirectUris(client.getRedirectUris());
+            }
+        }
+    }
+
+    public ClientRepresentation getValues() {
+        ClientRepresentation values = new ClientRepresentation();
+        values.setClientId(getClientId());
+        values.setName(getName());
+        values.setEnabled(isEnabled());
+        values.setConsentRequired(isConsentRequired());
+        values.setDirectGrantsOnly(isDirectGrantsOnly());
+        values.setProtocol(getProtocol());
+        if (OIDC.equals(values.getProtocol())) {
+            values.setBearerOnly(isBearerOnly());
+            if (!values.isBearerOnly()) {
+                values.setPublicClient(isPublicClient());
+                if (!values.isPublicClient()) {
+                    values.setServiceAccountsEnabled(isServiceAccountsEnabled());
+                }
+                values.setRedirectUris(getRedirectUris());
+            }
+        }
+        return values;
+    }
+
+    public String getClientId() {
+        return getInputValue(clientIdInput);
+    }
+
+    public void setClientId(String clientId) {
+        setInputValue(clientIdInput, clientId);
+    }
+
+    public String getName() {
+        return getInputValue(nameInput);
+    }
+
+    public void setName(String name) {
+        setInputValue(nameInput, name);
+    }
+
+    public boolean isEnabled() {
+        return enabledSwitch.isOn();
+    }
+
+    public void setEnabled(boolean enabled) {
+        enabledSwitch.setOn(enabled);
+    }
+
+    public static final String BEARER_ONLY = "bearer-only";
+    public static final String PUBLIC = "public";
+    public static final String CONFIDENTIAL = "confidential";
+
+    public boolean isBearerOnly() {
+        return BEARER_ONLY.equals(
+                accessTypeSelect.getFirstSelectedOption().getAttribute(VALUE));
+    }
+
+    public boolean isPublicClient() {
+        return PUBLIC.equals(
+                accessTypeSelect.getFirstSelectedOption().getAttribute(VALUE));
+    }
+
+    public void setBearerOnly(boolean bearerOnly) {
+        accessTypeSelectElement.sendKeys(BEARER_ONLY);
+//        accessTypeSelect.selectByVisibleText(BEARER_ONLY);
+    }
+
+    public void setPublicClient(boolean publicClient) {
+        accessTypeSelectElement.sendKeys(PUBLIC);
+//        accessTypeSelect.selectByVisibleText(PUBLIC);
+    }
+
+    public void setAccessType(ClientRepresentation client) { // TODO verify
+        setBearerOnly(client.isBearerOnly());
+        setPublicClient(client.isPublicClient());
+        if (!client.isBearerOnly() && !client.isPublicClient()) {
+            accessTypeSelect.selectByVisibleText(CONFIDENTIAL);
+        }
+    }
+
+    public void addRedirectUri(String redirectUri) {
+        newRedirectUriInput.sendKeys(redirectUri);
+    }
+
+    public List<String> getRedirectUris() {
+        List<String> values = new ArrayList<>();
+        for (WebElement input : redirectUriInputs) {
+            values.add(getInputValue(input));
+        }
+        return values;
+    }
+
+    public void setRedirectUris(List<String> redirectUris) {
+        Timer.time();
+        while (!deleteRedirectUriIcons.isEmpty()) {
+            deleteRedirectUriIcons.get(0).click();
+            pause(100);
+        }
+        Timer.time("deleteRedirectUris");
+        if (redirectUris != null) {
+            for (String redirectUri : redirectUris) {
+                addRedirectUri(redirectUri);
+                pause(100);
+            }
+        }
+        Timer.time("addRedirectUris");
+    }
+
+    public boolean isConsentRequired() {
+        return consentRequiredSwitch.isOn();
+    }
+
+    public void setConsentRequired(boolean consentRequired) {
+        consentRequiredSwitch.setOn(consentRequired);
+    }
+
+    public boolean isDirectGrantsOnly() {
+        return directGrantsOnlySwitch.isOn();
+    }
+
+    public void setDirectGrantsOnly(boolean directGrantsOnly) {
+        directGrantsOnlySwitch.setOn(directGrantsOnly);
+    }
+
+    public String getProtocol() {
+        waitAjaxForElement(protocolSelect.getFirstSelectedOption());
+        return protocolSelect.getFirstSelectedOption().getText();
+    }
+
+    public void setProtocol(String protocol) {
+        Timer.time();
+        protocolSelectElement.sendKeys(protocol);
+        Timer.time("clientSettings.setProtocol()");
+    }
+
+    public boolean isServiceAccountsEnabled() {
+        return serviceAccountsEnabledSwitch.isOn();
+    }
+
+    public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
+        serviceAccountsEnabledSwitch.setOn(serviceAccountsEnabled);
+    }
+
+    public class SAMLClientSettingsForm extends Form {
+
+        // TODO add SAML client attributes
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java
new file mode 100644
index 0000000..8a3317a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import static org.keycloak.testsuite.console.page.clients.Client.ID;
+import org.keycloak.testsuite.console.page.roles.CreateRole;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateClientRole extends CreateRole {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/clients/{" + ID + "}";
+    }
+
+    public void setClientId(String id) {
+        setUriParameter(ID, id);
+    }
+
+    public String getClientId() {
+        return getUriParameter(ID).toString();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java
new file mode 100644
index 0000000..08e0e00
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java
@@ -0,0 +1,104 @@
+package org.keycloak.testsuite.console.page.events;
+
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class AdminEvents extends Events {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/admin-events";
+    }
+
+    @FindBy(tagName = "table")
+    private AdminEventsTable table;
+
+    public AdminEventsTable table() {
+        return table;
+    }
+
+    public class AdminEventsTable extends DataTable {
+
+        public void update() {
+            waitAjaxForBody();
+            clickHeaderButton("Update");
+        }
+
+        public void reset() {
+            waitAjaxForBody();
+            clickHeaderButton("Reset");
+        }
+
+        @FindBy(xpath = "//button[text()[contains(.,'Filter')]]")
+        private WebElement filterButton;
+
+        public void filter() {
+            waitAjaxForBody();
+            filterButton.click();
+        }
+
+        @FindBy(tagName = "form")
+        private AdminEventsTableFilterForm filterForm;
+
+        public AdminEventsTableFilterForm filterForm() {
+            return filterForm;
+        }
+
+        public class AdminEventsTableFilterForm extends Form {
+
+            public void addOperationType(String type) {
+                driver.findElement(By.xpath("//div[@id='s2id_adminEnabledEventOperations']/ul")).click();
+                driver.findElement(By.xpath("//div[@id='select2-drop']//div[text()[contains(.,'" + type + "')]]/..")).click();
+            }
+
+            public void removeOperationType(String type) {
+                driver.findElement(By.xpath("//div[@id='s2id_adminEnabledEventOperations']//div[text()='" + type + "']/../a")).click();
+            }
+
+            @FindBy(id = "resource")
+            private WebElement resourcePathInput;
+
+            public void setResourcePathInput(String value) {
+                setInputValue(resourcePathInput, value);
+            }
+
+            @FindBy(id = "realm")
+            private WebElement realmInput;
+
+            public void setRealmInput(String value) {
+                setInputValue(realmInput, value);
+            }
+
+            @FindBy(id = "client")
+            private WebElement clientInput;
+
+            public void setClientInput(String value) {
+                setInputValue(clientInput, value);
+            }
+
+            @FindBy(id = "user")
+            private WebElement userInput;
+
+            public void setUserInput(String value) {
+                setInputValue(userInput, value);
+            }
+
+            @FindBy(id = "ipAddress")
+            private WebElement ipAddressInput;
+
+            public void setIpAddressInput(String value) {
+                setInputValue(ipAddressInput, value);
+            }
+        }
+
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Config.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Config.java
new file mode 100644
index 0000000..686e902
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Config.java
@@ -0,0 +1,99 @@
+package org.keycloak.testsuite.console.page.events;
+
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class Config extends Events {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/events-settings";
+    }
+
+    @FindBy(xpath = "//form")
+    private ConfigForm form;
+
+    public ConfigForm form() {
+        return form;
+    }
+
+    public class ConfigForm extends Form {
+        @FindBy(id = "s2id_autogen1")
+        private WebElement eventListenersInput;
+
+        @FindBy(xpath = "//div[@id='s2id_autogen1']/..//select")
+        private Select eventListenersSelect;
+
+        public void addEventListener(String listener) {
+            eventListenersInput.click();
+            eventListenersSelect.selectByVisibleText(listener);
+        }
+
+        public void removeEventListener(String listener) {
+            eventListenersInput.findElement(By.xpath("//div[text()='" + listener + "']/../a")).click();
+        }
+
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='enabled']]")
+        private OnOffSwitch SaveEvents;
+
+        public void setSaveEvents(boolean value) {
+            SaveEvents.setOn(value);
+        }
+
+        @FindBy(xpath = "//div[@id='s2id_enabledEventTypes']//input")
+        private WebElement savedTypesInput;
+
+        @FindBy(xpath = "//div[@id='select2-drop']/ul")
+        private WebElement savedTypesOptions;
+
+        public void addSaveType(String type) {
+            savedTypesInput.click();
+            savedTypesOptions.findElement(By.xpath("//div[text()='" + type + "']")).click();
+        }
+
+        public void removeSaveType(String type) {
+            savedTypesInput.findElement(By.xpath("//div[text()='" + type + "']/../a")).click();
+        }
+
+        public void clearLoginEvents() {
+            driver.findElement(By.xpath("//button[@data-ng-click='clearEvents()']")).click();
+        }
+
+        @FindBy(id = "expiration")
+        private WebElement expirationInput;
+
+        @FindBy(name = "expirationUnit")
+        private Select expirationUnitSelect;
+
+        public void setExpiration(String value, String unit) {
+            expirationUnitSelect.selectByVisibleText(unit);
+            Form.setInputValue(expirationInput, value);
+        }
+
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='adminEventsEnabled']]")
+        private OnOffSwitch saveAdminEvents;
+
+        public void setSaveAdminEvents(boolean value) {
+            saveAdminEvents.setOn(value);
+        }
+
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='adminEventsDetailsEnabled']]")
+        private OnOffSwitch includeRepresentation;
+
+        public void setIncludeRepresentation(boolean value) {
+            includeRepresentation.setOn(value);
+        }
+
+        public void clearAdminEvents() {
+            driver.findElement(By.xpath("//button[@data-ng-click='clearAdminEvents()']")).click();
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Events.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Events.java
new file mode 100644
index 0000000..53c8345
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Events.java
@@ -0,0 +1,35 @@
+package org.keycloak.testsuite.console.page.events;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Events extends AdminConsoleRealm {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment();
+    }
+    
+    @FindBy(linkText = "Login Events")
+    private WebElement loginEventsTab;
+    @FindBy(linkText = "Admin Events")
+    private WebElement adminEventsTab;
+    @FindBy(linkText = "Config")
+    private WebElement configTab;
+    
+    public void loginEvents() {
+        loginEventsTab.click();
+    }
+    public void adminEvents() {
+        adminEventsTab.click();
+    }
+    public void config() {
+        configTab.click();
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java
new file mode 100644
index 0000000..6752951
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java
@@ -0,0 +1,80 @@
+package org.keycloak.testsuite.console.page.events;
+
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class LoginEvents extends Events {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/events";
+    }
+
+    @FindBy(tagName = "table")
+    private LoginEventsTable table;
+
+    public LoginEventsTable table() {
+        return table;
+    }
+
+    public class LoginEventsTable extends DataTable {
+
+        public void update() {
+            waitAjaxForBody();
+            clickHeaderButton("Update");
+        }
+
+        public void reset() {
+            waitAjaxForBody();
+            clickHeaderButton("Reset");
+        }
+
+        @FindBy(xpath = "//button[text()[contains(.,'Filter')]]")
+        private WebElement filterButton;
+
+        public void filter() {
+            waitAjaxForBody();
+            filterButton.click();
+        }
+
+        @FindBy(tagName = "form")
+        private LoginEventsTableFilterForm filterForm;
+
+        public LoginEventsTableFilterForm filterForm() {
+            return filterForm;
+        }
+
+        public class LoginEventsTableFilterForm extends Form {
+
+            public void addEventType(String type) {
+                driver.findElement(By.xpath("//div[@id='s2id_eventTypes']/ul")).click();
+                driver.findElement(By.xpath("//div[@id='select2-drop']//div[text()='" + type + "']/..")).click();
+            }
+
+            public void removeOperationType(String type) {
+                driver.findElement(By.xpath("//div[@id='s2id_eventTypes']//div[text()='" + type + "']/../a")).click();
+            }
+
+            @FindBy(id = "client")
+            private WebElement clientInput;
+
+            public void setClientInput(String value) {
+                setInputValue(clientInput, value);
+            }
+
+            @FindBy(id = "user")
+            private WebElement userInput;
+
+            public void setUserInput(String value) {
+                setInputValue(userInput, value);
+            }
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/CreateLdapUserProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/CreateLdapUserProvider.java
new file mode 100644
index 0000000..4dc47f9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/CreateLdapUserProvider.java
@@ -0,0 +1,20 @@
+package org.keycloak.testsuite.console.page.federation;
+
+import org.keycloak.testsuite.console.page.AdminConsoleCreate;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateLdapUserProvider extends AdminConsoleCreate {
+
+    public CreateLdapUserProvider() {
+        setEntity("user-federation");
+    }
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/providers/ldap";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/LdapUserProviderForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/LdapUserProviderForm.java
new file mode 100644
index 0000000..a9b8882
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/LdapUserProviderForm.java
@@ -0,0 +1,130 @@
+package org.keycloak.testsuite.console.page.federation;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+
+/**
+ * Created by fkiss.
+ */
+public class LdapUserProviderForm extends Form {
+
+    @FindBy(id = "consoleDisplayName")
+    private WebElement consoleDisplayNameInput;
+
+    @FindBy(id = "priority")
+    private WebElement priorityInput;
+
+    @FindBy(id = "usernameLDAPAttribute")
+    private WebElement usernameLDAPAttributeInput;
+
+    @FindBy(id = "userObjectClasses")
+    private WebElement userObjectClassesInput;
+
+    @FindBy(id = "ldapConnectionUrl")
+    private WebElement ldapConnectionUrlInput;
+
+    @FindBy(id = "ldapBaseDn")
+    private WebElement ldapBaseDnInput;
+
+    @FindBy(id = "ldapUsersDn")
+    private WebElement ldapUserDnInput;
+
+    @FindBy(id = "ldapBindDn")
+    private WebElement ldapBindDnInput;
+
+    @FindBy(id = "ldapBindCredential")
+    private WebElement ldapBindCredentialInput;
+
+    @FindBy(id = "kerberosRealm")
+    private WebElement kerberosRealmInput;
+
+    @FindBy(id = "serverPrincipal")
+    private WebElement serverPrincipalInput;
+
+    @FindBy(id = "keyTab")
+    private WebElement keyTabInput;
+
+    @FindBy(id = "batchSizeForSync")
+    private WebElement batchSizeForSyncInput;
+
+    @FindBy(id = "fullSyncPeriod")
+    private WebElement fullSyncPeriodInput;
+
+    @FindBy(id = "changedSyncPeriod")
+    private WebElement changedSyncPeriodInput;
+
+    @FindBy(id = "editMode")
+    private Select editModeSelect;
+
+    @FindBy(id = "vendor")
+    private Select vendorSelect;
+
+    @FindByJQuery("a:contains('Test connection')")
+    private WebElement testConnectionButton;
+
+    @FindByJQuery("a:contains('Test authentication')")
+    private WebElement testAuthenticationButton;
+
+    @FindByJQuery("div[class='onoffswitch']:eq(0)")
+    private OnOffSwitch syncRegistrations;
+
+    @FindByJQuery("div[class='onoffswitch']:eq(1)")
+    private OnOffSwitch connectionPooling;
+
+    @FindByJQuery("div[class='onoffswitch']:eq(2)")
+    private OnOffSwitch pagination;
+
+    @FindByJQuery("div[class='onoffswitch']:eq(3)")
+    private OnOffSwitch allowKerberosAuth;
+
+    @FindByJQuery("div[class='onoffswitch']:eq(4)")
+    private OnOffSwitch debug;
+
+    @FindByJQuery("div[class='onoffswitch']:eq(5)")
+    private OnOffSwitch useKerberosForPwdAuth;
+
+    @FindByJQuery("div[class='onoffswitch']:eq(6)")
+    private OnOffSwitch periodicFullSync;
+
+    @FindByJQuery("div[class='onoffswitch']:eq(7)")
+    private OnOffSwitch periodicChangedUsersSync;
+
+    @FindByJQuery("button:contains('Save')")
+    private WebElement saveButton;
+
+    public void selectEditMode(String mode){
+        waitGuiForElement(By.id("editMode"));
+        editModeSelect.selectByVisibleText(mode);
+    }
+
+    public void selectVendor(String vendor){
+        waitGuiForElement(By.id("editMode"));
+        vendorSelect.selectByVisibleText(vendor);
+    }
+
+    public void configureLdap(String displayName, String editMode, String vendor, String connectionUrl, String userDN, String ldapBindDn, String ldapBindCredential){
+        consoleDisplayNameInput.sendKeys(displayName);
+        editModeSelect.selectByVisibleText(editMode);
+        selectVendor(vendor);
+        ldapConnectionUrlInput.sendKeys(connectionUrl);
+        ldapUserDnInput.sendKeys(userDN);
+        ldapBindDnInput.sendKeys(ldapBindDn);
+        ldapBindCredentialInput.sendKeys(ldapBindCredential);
+        saveButton.click();
+    }
+
+    public void testConnection(){
+        testConnectionButton.click();
+    }
+
+    public void testAuthentication(){
+        testAuthenticationButton.click();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/UserFederation.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/UserFederation.java
new file mode 100644
index 0000000..b209b81
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/UserFederation.java
@@ -0,0 +1,28 @@
+package org.keycloak.testsuite.console.page.federation;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.By;
+import org.openqa.selenium.support.ui.Select;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+
+/**
+ * Created by fkiss.
+ */
+public class UserFederation extends AdminConsoleRealm {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/user-federation";
+    }
+
+    @FindByJQuery("select[ng-model*='selectedProvider']")
+    private Select addProviderSelect;
+
+    public void addProvider(String provider) {
+        waitGuiForElement(By.cssSelector("select[ng-model*='selectedProvider']"));
+        addProviderSelect.selectByVisibleText(provider);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/Breadcrumb.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/Breadcrumb.java
new file mode 100644
index 0000000..d6d517b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/Breadcrumb.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+import java.util.List;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Breadcrumb {
+
+    public static final String BREADCRUMB_XPATH = "//ol[@class='breadcrumb']";
+
+    @FindBy(xpath = "./li[not(contains(@class,'ng-hide'))]/a")
+    private List<WebElement> items;
+
+    public int size() {
+        return items.size();
+    }
+
+    public WebElement getItem(int index) {
+        return items.get(index);
+    }
+
+    public WebElement getItemFromEnd(int index) {
+        return items.get(size() - index - 1);
+    }
+
+    public void clickItemOneLevelUp() {
+        getItemFromEnd(0).click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java
new file mode 100644
index 0000000..d049d2e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java
@@ -0,0 +1,76 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+import java.util.List;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.openqa.selenium.By;
+import static org.openqa.selenium.By.xpath;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class DataTable {
+
+    @FindBy(css = "input[class*='search']")
+    private WebElement searchInput;
+    @FindBy(css = "div[class='input-group-addon'] i")
+    private WebElement searchButton;
+
+    @FindBy(tagName = "thead")
+    private WebElement header;
+    @FindBy(css = "tbody")
+    private WebElement body;
+    @FindBy(css = "tbody tr.ng-scope")
+    private List<WebElement> rows;
+    
+    @FindBy
+    private WebElement infoRow;
+
+    public void search(String pattern) {
+        waitAjaxForBody();
+        searchInput.sendKeys(pattern);
+        searchButton.click();
+    }
+
+    public void clickHeaderButton(String buttonText) {
+        waitAjaxForBody();
+        header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click();
+    }
+
+    public void clickHeaderLink(String linkText) {
+        waitAjaxForBody();
+        header.findElement(By.linkText(linkText)).click();
+    }
+
+    public WebElement body() {
+        return body;
+    }
+
+    public void waitAjaxForBody() {
+        waitAjaxForElement(body);
+    }
+
+    public List<WebElement> rows() {
+        waitAjaxForBody();
+        pause(250);
+        return rows;
+    }
+
+    public WebElement getRowByLinkText(String text) {
+        WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]"));
+        waitAjaxForElement(row);
+        return row;
+    }
+
+    public void clickRowByLinkText(String text) {
+        body.findElement(By.xpath(".//tr/td/a[text()='" + text + "']")).click();
+    }
+
+    public void clickRowActionButton(WebElement row, String buttonText) {
+        row.findElement(xpath(".//button[text()='" + buttonText + "']")).click();
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/InputList.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/InputList.java
new file mode 100644
index 0000000..902287e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/InputList.java
@@ -0,0 +1,28 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+import java.util.ArrayList;
+import java.util.List;
+import static org.keycloak.testsuite.page.Form.getInputValue;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class InputList {
+    
+    @FindBy(xpath=".//input[@ng-model='client.redirectUris[i]']")
+    private List<WebElement> inputs;
+    
+    public List<String> getValues() {
+        List<String> values = new ArrayList<>();
+        for (WebElement input: inputs) {
+            values.add(getInputValue(input));
+        }
+        return values;
+    }
+    
+    
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
new file mode 100644
index 0000000..9bb95dd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
@@ -0,0 +1,36 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ModalDialog {
+
+    @FindBy(xpath = ".//button[text()='Cancel']")
+    private WebElement cancelButton;
+    @FindBy(xpath = ".//button[text()='Delete']")
+    private WebElement deleteButton;
+
+    @FindBy(xpath = ".//button[@ng-click='ok()']")
+    private WebElement okButton;
+
+    public void ok() {
+        waitAjaxForElement(okButton);
+        okButton.click();
+    }
+    
+    public void confirmDeletion() {
+        waitAjaxForElement(deleteButton);
+        deleteButton.click();
+    }
+
+    public void cancel() {
+        waitAjaxForElement(cancelButton);
+        cancelButton.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/RealmSelector.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/RealmSelector.java
new file mode 100644
index 0000000..5e2ea52
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/RealmSelector.java
@@ -0,0 +1,11 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RealmSelector {
+    
+    // TODO
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/CacheSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/CacheSettings.java
new file mode 100644
index 0000000..e903f01
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/CacheSettings.java
@@ -0,0 +1,42 @@
+package org.keycloak.testsuite.console.page.realm;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class CacheSettings extends RealmSettings {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/cache-settings";
+    }
+
+    @Page
+    private CacheSettingsForm form;
+
+    public CacheSettingsForm form() {
+        return form;
+    }
+
+    public class CacheSettingsForm extends Form {
+        @FindByJQuery("div[class='onoffswitch']:eq(0)")
+        private OnOffSwitch realmCacheEnabled;
+
+        @FindByJQuery("div[class='onoffswitch']:eq(1)")
+        private OnOffSwitch userCacheEnabled;
+
+        public void setRealmCacheEnabled(boolean value) {
+            realmCacheEnabled.setOn(value);
+        }
+
+        public void setUserCacheEnabled(boolean value) {
+            userCacheEnabled.setOn(value);
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/EmailSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/EmailSettings.java
new file mode 100644
index 0000000..f75117b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/EmailSettings.java
@@ -0,0 +1,70 @@
+package org.keycloak.testsuite.console.page.realm;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * Created by mhajas on 8/25/15.
+ */
+public class EmailSettings extends RealmSettings {
+    
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/smtp-settings";
+    }
+
+    @Page
+    private EmailSettingsForm form;
+
+    public EmailSettingsForm form() {
+        return form;
+    }
+
+    public class EmailSettingsForm extends Form {
+        @FindBy(id = "smtpHost")
+        private WebElement hostInput;
+
+        @FindBy(id = "smtpPort")
+        private WebElement portInput;
+
+        @FindBy(id = "smtpFrom")
+        private WebElement fromInput;
+
+        @FindByJQuery("div[class='onoffswitch']:eq(0)")
+        private OnOffSwitch enableSSL;
+
+        @FindByJQuery("div[class='onoffswitch']:eq(1)")
+        private OnOffSwitch enableStartTLS;
+
+        @FindByJQuery("div[class='onoffswitch']:eq(2)")
+        private OnOffSwitch enableAuthentication;
+
+        public void setEnableSSL(boolean sslEnabled) {
+            enableSSL.setOn(sslEnabled);
+        }
+
+        public void setEnableStartTLS(boolean startTLS) {
+            enableSSL.setOn(startTLS);
+        }
+
+        public void setEnableAuthentication(boolean authentication) {
+            enableSSL.setOn(authentication);
+        }
+
+        public void setHostInput(String value) {
+            setInputValue(hostInput, value);
+        }
+
+        public void setPortInput(String value) {
+            setInputValue(portInput, value);
+        }
+
+        public void setFromInput(String value) {
+            setInputValue(fromInput, value);
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/KeysSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/KeysSettings.java
new file mode 100644
index 0000000..902acf0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/KeysSettings.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.realm;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class KeysSettings extends RealmSettings {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/cache-settings";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/RealmSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/RealmSettings.java
new file mode 100644
index 0000000..83b1a67
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/RealmSettings.java
@@ -0,0 +1,72 @@
+package org.keycloak.testsuite.console.page.realm;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RealmSettings extends AdminConsoleRealm {
+
+    @FindBy(xpath = "//div[@data-ng-controller='RealmTabCtrl']/ul")
+    private RealmTabs realmTabs;
+
+    public RealmTabs tabs() {
+        return realmTabs;
+    }
+
+    public class RealmTabs {
+
+        @FindBy(linkText = "General")
+        private WebElement generalSettingsTab;
+        @FindBy(linkText = "Login")
+        private WebElement loginSettingsTab;
+        @FindBy(linkText = "Keys")
+        private WebElement keysSettingsTab;
+        @FindBy(linkText = "Email")
+        private WebElement emailSettingsTab;
+        @FindBy(linkText = "Themes")
+        private WebElement themeSettingsTab;
+        @FindBy(linkText = "Cache")
+        private WebElement cacheSettingsTab;
+        @FindBy(linkText = "Tokens")
+        private WebElement tokenSettingsTab;
+        @FindBy(linkText = "Security Defenses")
+        private WebElement defenseTab;
+
+        public void general() {
+            generalSettingsTab.click();
+        }
+
+        public void login() {
+            loginSettingsTab.click();
+        }
+
+        public void keys() {
+            keysSettingsTab.click();
+        }
+
+        public void email() {
+            emailSettingsTab.click();
+        }
+
+        public void themes() {
+            themeSettingsTab.click();
+        }
+
+        public void cache() {
+            cacheSettingsTab.click();
+        }
+
+        public void tokens() {
+            tokenSettingsTab.click();
+        }
+
+        public void securityDefenses() {
+            defenseTab.click();
+        }
+
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/SecurityDefenses.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/SecurityDefenses.java
new file mode 100644
index 0000000..00bd0b8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/SecurityDefenses.java
@@ -0,0 +1,197 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.page.realm;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.page.Form.setInputValue;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author Filip Kiss
+ * @author mhajas
+ */
+public class SecurityDefenses extends RealmSettings {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/defense"; // NOTE: page doesn't exist, only subpages
+    }
+
+    public class Headers extends SecurityDefenses {
+
+        @Override
+        public String getUriFragment() {
+            return super.getUriFragment() + "/headers";
+        }
+
+        @Page
+        private HeadersForm form;
+
+        public HeadersForm form() {
+            return form;
+        }
+
+        public class HeadersForm extends Form {
+
+            @FindBy(id = "xFrameOptions")
+            private WebElement xFrameOptions;
+
+            public void setXFrameOptions(String value) {
+                setInputValue(xFrameOptions, value);
+            }
+
+            @FindBy(id = "contentSecurityPolicy")
+            private WebElement contentSecurityPolicy;
+
+            public void setContentSecurityPolicy(String value) {
+                setInputValue(contentSecurityPolicy, value);
+            }
+        }
+    }
+
+    public enum TimeSelectValues {
+
+        SECONDS("Seconds"), MINUTES("Minutes"), HOURS("Hours"), DAYS("Days");
+
+        private String name;
+
+        private TimeSelectValues(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    public class BruteForceDetection extends SecurityDefenses {
+
+        @Override
+        public String getUriFragment() {
+            return super.getUriFragment() + "/brute-force";
+        }
+
+        @Page
+        private BruteForceDetectionForm form;
+
+        public BruteForceDetectionForm form() {
+            return form;
+        }
+
+        public class BruteForceDetectionForm extends Form {
+
+            @FindByJQuery("div[class='onoffswitch']")
+            private OnOffSwitch protectionEnabled;
+
+            public void setProtectionEnabled(boolean protectionEnabled) {
+                this.protectionEnabled.setOn(protectionEnabled);
+            }
+
+            @FindBy(id = "failureFactor")
+            private WebElement maxLoginFailures;
+
+            public void setMaxLoginFailures(String value) {
+                setInputValue(maxLoginFailures, value);
+            }
+
+            @FindBy(id = "waitIncrement")
+            private WebElement waitIncrementInput;
+
+            @FindBy(name = "waitIncrementUnit")
+            private Select waitIncrementSelect;
+
+            public void setWaitIncrementInput(String value) {
+                setInputValue(waitIncrementInput, value);
+            }
+
+            public void setWaitIncrementSelect(TimeSelectValues value) {
+                waitIncrementSelect.selectByVisibleText(value.getName());
+            }
+
+            @FindBy(id = "quickLoginCheckMilliSeconds")
+            private WebElement quickLoginCheckInput;
+
+            public void setQuickLoginCheckInput(String value) {
+                setInputValue(quickLoginCheckInput, value);
+            }
+
+            @FindBy(id = "minimumQuickLoginWait")
+            private WebElement minQuickLoginWaitInput;
+
+            @FindBy(name = "minimumQuickLoginWaitUnit")
+            private Select minQuickLoginWaitSelect;
+
+            public void setMinQuickLoginWaitInput(String value) {
+                setInputValue(minQuickLoginWaitInput, value);
+            }
+
+            public void setMinQuickLoginWaitSelect(TimeSelectValues value) {
+                minQuickLoginWaitSelect.selectByVisibleText(value.getName());
+            }
+
+            @FindBy(id = "maxFailureWait")
+            private WebElement maxWaitInput;
+
+            @FindBy(name = "maxFailureWaitUnit")
+            private Select maxWaitSelect;
+
+            public void setMaxWaitInput(String value) {
+                setInputValue(maxWaitInput, value);
+            }
+
+            public void setMaxWaitSelect(TimeSelectValues value) {
+                maxWaitSelect.selectByVisibleText(value.getName());
+            }
+
+            @FindBy(id = "maxDeltaTime")
+            private WebElement failureResetTimeInput;
+
+            @FindBy(name = "maxDeltaTimeUnit")
+            private Select failureResetTimeSelect;
+
+            public void setFailureResetTimeInput(String value) {
+                setInputValue(failureResetTimeInput, value);
+            }
+
+            public void setFailureResetTimeSelect(TimeSelectValues value) {
+                failureResetTimeSelect.selectByVisibleText(value.getName());
+            }
+
+        }
+
+    }
+
+    @FindByJQuery("a:contains('Brute Force Detection')")
+    private WebElement bruteForceDetectionTab;
+
+    public void goToBruteForceDetection() {
+        bruteForceDetectionTab.click();
+    }
+
+    @FindByJQuery("a:contains('Headers')")
+    private WebElement headersTab;
+
+    public void goToHeaders() {
+        headersTab.click();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/CreateRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/CreateRole.java
new file mode 100644
index 0000000..d1f218b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/CreateRole.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.AdminConsoleCreate;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateRole extends AdminConsoleCreate {
+
+    public CreateRole() {
+        setEntity("role");
+    }
+
+    @Page
+    private RoleForm form;
+    
+    public RoleForm form() {
+        return form;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Role.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Role.java
new file mode 100644
index 0000000..2bde155
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Role.java
@@ -0,0 +1,33 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Role extends RealmRoles {
+
+    public static final String ROLE_ID = "roleId";
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/{" + ROLE_ID + "}";
+    }
+
+    public void setRoleId(String id) {
+        setUriParameter(ROLE_ID, id);
+    }
+
+    public String getRoleId() {
+        return getUriParameter(ROLE_ID).toString();
+    }
+
+    @Page
+    private RoleForm form;
+
+    public RoleForm form() {
+        return form;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java
new file mode 100644
index 0000000..876b45b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java
@@ -0,0 +1,182 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.keycloak.representations.idm.RoleRepresentation.Composites;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author fkiss
+ * @author tkyjovsk
+ */
+public class RoleCompositeRoles extends Form {
+
+    @FindBy(id = "available")
+    protected Select availableRealmRolesSelect;
+    @FindBy(id = "assigned")
+    protected Select assignedRealmRolesSelect;
+
+    @FindBy(id = "clients")
+    protected Select clientSelect;
+    @FindBy(id = "available-client")
+    protected Select availableClientRolesSelect;
+    @FindBy(id = "assigned-client")
+    protected Select assignedClientRolesSelect;
+
+    @FindBy(css = "button[ng-click*='addRealm']")
+    protected WebElement addSelectedRealmRolesButton;
+    @FindBy(css = "button[ng-click*='addClient']")
+    protected WebElement addSelectedClientRolesButton;
+    @FindBy(css = "button[ng-click*='deleteRealm']")
+    protected WebElement removeSelectedRealmRolesButton;
+    @FindBy(css = "button[ng-click*='deleteClient']")
+    protected WebElement removeSelectedClientRolesButton;
+
+    public Composites getComposites() {
+        Composites composites = new Composites();
+        // realm roles
+        composites.setRealm(getSelectValues(assignedRealmRolesSelect));
+        // client roles
+        Map<String, List<String>> clientRoles = new HashMap<>();
+        for (String client : getSelectValues(clientSelect)) {
+            clientSelect.selectByVisibleText(client);
+            clientRoles.put(client, new ArrayList(getSelectValues(assignedClientRolesSelect)));
+        }
+        composites.setClient(clientRoles);
+        return composites;
+    }
+
+    public void setComposites(Composites composites) {
+        if (composites != null) {
+            setRealmRoles(composites.getRealm());
+            for (String client : composites.getClient().keySet()) {
+                clientSelect.selectByVisibleText(client);
+                setClientRoles(composites.getClient().get(client));
+            }
+        }
+    }
+
+    private void setRealmRoles(Collection<String> roles) {
+        removeRedundantRoles(assignedRealmRolesSelect, removeSelectedRealmRolesButton, roles);
+        addMissingRoles(availableRealmRolesSelect, addSelectedRealmRolesButton, roles);
+    }
+
+    private void setClientRoles(Collection<String> roles) {
+        removeRedundantRoles(assignedClientRolesSelect, removeSelectedClientRolesButton, roles);
+        addMissingRoles(availableClientRolesSelect, addSelectedClientRolesButton, roles);
+    }
+
+    private void removeRedundantRoles(Select select, WebElement button, Collection<String> roles) {
+        select.deselectAll();
+        for (String role : getSelectValues(select)) {
+            if (roles == null // if roles not provided, remove all
+                    || !roles.contains(role)) { // if roles provided, remove only the redundant
+                select.selectByVisibleText(role);
+            }
+        }
+        button.click();
+    }
+
+    protected void addMissingRoles(Select select, WebElement button, Collection<String> roles) {
+        select.deselectAll();
+        if (roles != null) { // if roles not provided, don't add any
+            for (String role : getSelectValues(select)) {
+                if (roles.contains(role)) { // if roles provided, add only the missing
+                    select.selectByVisibleText(role);
+                }
+            }
+            button.click();
+        }
+    }
+
+    public static Set<String> getSelectValues(Select select) {
+        Set<String> roles = new HashSet<>();
+        for (WebElement option : select.getOptions()) {
+            roles.add(option.getText());
+        }
+        return roles;
+    }
+
+    // ***
+    public Set<String> getAvailableRealmRoles() {
+        return getSelectValues(availableRealmRolesSelect);
+    }
+
+    public Set<String> getAvailableClientRoles(String client) {
+        return getSelectValues(availableClientRolesSelect);
+    }
+
+    public Set<String> getAssignedRealmRoles() {
+        return getSelectValues(assignedRealmRolesSelect);
+    }
+
+    public Set<String> getAssignedClientRoles() {
+        return getSelectValues(assignedClientRolesSelect);
+    }
+
+    // *** original methods ***
+    public void addAvailableRole(String... roles) {
+        waitGuiForElement(By.id("available"));
+        for (String role : roles) {
+            availableRealmRolesSelect.selectByVisibleText(role);
+            addSelectedRealmRolesButton.click();
+        }
+    }
+
+    public void removeAssignedRole(String role) {
+        waitGuiForElement(By.id("assigned"));
+        assignedRealmRolesSelect.selectByVisibleText(role);
+        removeSelectedRealmRolesButton.click();
+    }
+
+    public boolean isAssignedRole(String role) {
+        waitGuiForElement(By.id("assigned"));
+        try {
+            assignedRealmRolesSelect.selectByVisibleText(role);
+        } catch (Exception ex) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean isAssignedClientRole(String role) {
+        waitGuiForElement(By.id("assigned"));
+        try {
+            assignedClientRolesSelect.selectByVisibleText(role);
+        } catch (Exception ex) {
+            return false;
+        }
+        return true;
+    }
+
+    public void selectClientRole(String client) {
+        waitGuiForElement(By.id("clients"));
+        clientSelect.selectByVisibleText(client);
+    }
+
+    public void addAvailableClientRole(String... roles) {
+        waitGuiForElement(By.id("available-client"));
+        for (String role : roles) {
+            availableClientRolesSelect.selectByVisibleText(role);
+            addSelectedClientRolesButton.click();
+        }
+    }
+
+    public void removeAssignedClientRole(String client) {
+        waitGuiForElement(By.id("assigned-client"));
+        assignedClientRolesSelect.selectByVisibleText(client);
+        removeSelectedClientRolesButton.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleForm.java
new file mode 100644
index 0000000..ac1db15
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleForm.java
@@ -0,0 +1,101 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RoleForm extends Form {
+
+    @FindBy(id = "name")
+    private WebElement nameInput;
+
+    @FindBy(id = "description")
+    private WebElement descriptionInput;
+
+    @FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='compositeSwitch']]")
+    private OnOffSwitch compositeSwitch;
+
+    @FindBy(xpath = ".//fieldset[./legend[contains(text(),'Composite Roles')]]")
+    private RoleCompositeRoles compositeRoles;
+
+    @FindBy(id = "removeRole")
+    private WebElement removeIcon;
+
+    public RoleRepresentation getRole() {
+        RoleRepresentation role = new RoleRepresentation(getName(), getDescription());
+        role.setComposite(isComposite());
+        if (role.isComposite()) {
+            role.setComposites(compositeRoles.getComposites());
+        }
+        return role;
+    }
+
+    public void setRole(RoleRepresentation role) {
+        setBasicAttributes(role);
+    }
+
+    public RoleRepresentation getBasicAttributes() {
+        RoleRepresentation role = new RoleRepresentation();
+        role.setName(getName());
+        role.setDescription(getDescription());
+        role.setComposite(isComposite());
+        log.info(role.getName() + ": " + role.getDescription() + ", comp: " + role.isComposite());
+        return role;
+    }
+
+    public void setBasicAttributes(RoleRepresentation role) {
+        setName(role.getName());
+        setDescription(role.getDescription());
+        if (role.isComposite()) {
+            setCompositeRoles(role);
+        }
+    }
+
+    // TODO KEYCLOAK-1364 enabling/disabling composite role seems unintuitive
+    // it should be possible to remove all composite roles by switching to OFF
+    public void setCompositeRoles(RoleRepresentation role) {
+        if (role.isComposite() && role.getComposites() != null) {
+            setComposite(true);
+        }
+        compositeRoles.setComposites(role.getComposites());
+    }
+
+    public void setName(String name) {
+        setInputValue(nameInput, name);
+    }
+
+    public String getName() {
+        return getInputValue(nameInput);
+    }
+
+    public void setDescription(String description) {
+        setInputValue(descriptionInput, description);
+    }
+
+    public String getDescription() {
+        return getInputValue(descriptionInput);
+    }
+
+    public void setComposite(boolean composite) {
+        compositeSwitch.setOn(composite);
+    }
+
+    public boolean isComposite() {
+        return compositeSwitch.isOn();
+    }
+
+    public RoleCompositeRoles compositeRoles() {
+        return compositeRoles;
+    }
+
+    public void delete() {
+        removeIcon.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java
new file mode 100644
index 0000000..910e470
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java
@@ -0,0 +1,42 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import org.keycloak.admin.client.resource.RolesResource;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Roles extends AdminConsoleRealm {
+
+    @FindBy(css = "ul.nav-tabs")
+    private RoleTabs tabs;
+
+    public RoleTabs tabs() {
+        return tabs;
+    }
+
+    public class RoleTabs {
+
+        @FindBy(linkText = "Realm Roles")
+        private WebElement realmRolesTab;
+        @FindBy(linkText = "Default Roles")
+        private WebElement defaultRolesTab;
+
+        public void realmRoles() {
+            realmRolesTab.click();
+        }
+
+        public void defaultRoles() {
+            defaultRolesTab.click();
+        }
+
+    }
+
+    public RolesResource rolesResource() {
+        return realmResource().roles();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java
new file mode 100644
index 0000000..b215844
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java
@@ -0,0 +1,85 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+import static org.openqa.selenium.By.tagName;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RolesTable extends DataTable {
+
+    public static final String ADD_ROLE = "Add Role";
+
+    public static final String EDIT = "Edit";
+    public static final String DELETE = "Delete";
+
+    public List<RoleRepresentation> searchRoles(String searchPattern) {
+        search(searchPattern);
+        return getRolesFromTableRows();
+    }
+
+    public void addRole() {
+        clickHeaderLink(ADD_ROLE);
+    }
+
+    public void clickRole(String name) {
+        waitAjaxForBody();
+        clickRowByLinkText(name);
+    }
+
+    public void editRole(String name) {
+        clickRowActionButton(getRowByLinkText(name), EDIT);
+    }
+
+    public void deleteRole(String name) {
+        clickRowActionButton(getRowByLinkText(name), DELETE);
+    }
+
+    public RoleRepresentation findRole(String name) {
+        List<RoleRepresentation> roles = searchRoles(name);
+        if (roles.isEmpty()) {
+            return null;
+        } else {
+            assert 1 == roles.size();
+            return roles.get(0);
+        }
+    }
+
+    public boolean containsRole(String roleName) {
+        for (RoleRepresentation r : getRolesFromTableRows()) {
+            if (roleName.equals(r.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public List<RoleRepresentation> getRolesFromTableRows() {
+        List<RoleRepresentation> rows = new ArrayList<>();
+        for (WebElement row : rows()) {
+            RoleRepresentation role = getRoleFromRow(row);
+            if (role != null) {
+                rows.add(role);
+            }
+        }
+        return rows;
+    }
+
+    public RoleRepresentation getRoleFromRow(WebElement row) {
+        RoleRepresentation role = null;
+        List<WebElement> tds = row.findElements(tagName("td"));
+        if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
+            role = new RoleRepresentation();
+            role.setName(tds.get(0).getText());
+            role.setComposite(Boolean.valueOf(tds.get(1).getText()));
+            role.setDescription(tds.get(2).getText());
+        }
+        return role;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Revocation.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Revocation.java
new file mode 100644
index 0000000..0175848
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Revocation.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.sessions;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Revocation extends Sessions {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/revocation";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Sessions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Sessions.java
new file mode 100644
index 0000000..a0a8dba
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Sessions.java
@@ -0,0 +1,32 @@
+package org.keycloak.testsuite.console.page.sessions;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Sessions extends AdminConsoleRealm {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/sessions";
+    }
+
+    @FindBy(linkText = "Realm Sessions")
+    private WebElement realmSessionsTab;
+
+    @FindBy(linkText = "Revocation")
+    private WebElement revocationTab;
+
+    public void realmSessions() {
+        realmSessionsTab.click();
+    }
+
+    public void revocation() {
+        revocationTab.click();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/CreateUser.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/CreateUser.java
new file mode 100644
index 0000000..4cd0df6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/CreateUser.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.AdminConsoleCreate;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateUser extends AdminConsoleCreate {
+
+    public CreateUser() {
+        setEntity("user");
+    }
+    
+    @Page
+    private UserAttributesForm form;
+    
+    public UserAttributesForm form() {
+        return form;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/User.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/User.java
new file mode 100644
index 0000000..fba2adb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/User.java
@@ -0,0 +1,83 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.testsuite.console.page.fragment.Breadcrumb;
+import static org.keycloak.testsuite.console.page.fragment.Breadcrumb.BREADCRUMB_XPATH;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class User extends Users {
+
+    public static final String ID = "id";
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/{" + ID + "}";
+    }
+
+    public void setId(String id) {
+        setUriParameter(ID, id);
+    }
+
+    public String getId() {
+        return (String) getUriParameter(ID);
+    }
+
+    @FindBy(xpath = BREADCRUMB_XPATH)
+    private Breadcrumb breadcrumb;
+
+    public Breadcrumb breadcrumb() {
+        return breadcrumb;
+    }
+    
+    @FindBy(xpath = "//div[@data-ng-controller='UserTabCtrl']/ul")
+    protected UserTabs userTabs;
+
+    public UserTabs tabs() {
+        return userTabs;
+    }
+
+    public class UserTabs {
+
+        @FindBy(linkText = "Attributes")
+        private WebElement attributesLink;
+        @FindBy(linkText = "Credentials")
+        private WebElement credentialsLink;
+        @FindBy(linkText = "Role Mappings")
+        private WebElement roleMappingsLink;
+        @FindBy(linkText = "Consents")
+        private WebElement consentsLink;
+        @FindBy(linkText = "Sessions")
+        private WebElement sessionsLink;
+
+        public void attributes() {
+            attributesLink.click();
+        }
+
+        public void credentials() {
+            credentialsLink.click();
+        }
+
+        public void roleMappings() {
+            roleMappingsLink.click();
+        }
+
+        public void consents() {
+            consentsLink.click();
+        }
+
+        public void sessions() {
+            sessionsLink.click();
+        }
+
+    }
+    
+    public UserResource userResource() {
+        return usersResource().get(getId());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributes.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributes.java
new file mode 100644
index 0000000..ebe5218
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributes.java
@@ -0,0 +1,22 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserAttributes extends User {
+
+    @FindBy(name = "userForm")
+    private UserAttributesForm form;
+
+    public UserAttributesForm form() {
+        return form;
+    }
+
+    public void backToUsersViaBreadcrumb() {
+        breadcrumb().clickItemOneLevelUp();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java
new file mode 100644
index 0000000..85b32e6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java
@@ -0,0 +1,139 @@
+package org.keycloak.testsuite.console.page.users;
+
+import java.util.List;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author Filip Kiss
+ * @author tkyjovsk
+ */
+public class UserAttributesForm extends Form {
+
+    @FindBy(id = "id")
+    private WebElement idInput;
+
+    @FindBy(id = "username")
+    private WebElement usernameInput;
+
+    @FindBy(id = "email")
+    private WebElement emailInput;
+
+    @FindBy(id = "firstName")
+    private WebElement firstNameInput;
+
+    @FindBy(id = "lastName")
+    private WebElement lastNameInput;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='userEnabled']]")
+    private OnOffSwitch userEnabledSwitch;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='emailVerified']]")
+    private OnOffSwitch emailVerifiedSwitch;
+
+    @FindBy(xpath = ".//div[./label[contains(text(), 'Required User Actions')]]//input")
+    private WebElement requiredUserActionsInput;
+
+    @FindBy(id = "reqActions")
+    private Select requiredUserActionsSelect;
+
+    @FindBy(className = "select2-result-label")
+    private WebElement requiredUserActionsConfirm;
+
+    @FindBy(className = "select2-search-choice-close")
+    private List<WebElement> removeRequiredActionsList;
+
+    @FindBy(xpath = "//button[@data-ng-click='unlockUser()']")
+    private WebElement unlockUserButton;
+
+    public String getId() {
+        return getInputValue(idInput);
+    }
+
+    public String getUsername() {
+        return getInputValue(usernameInput);
+    }
+
+    public void setUsername(String username) {
+        setInputValue(usernameInput, username);
+    }
+
+    public String getEmail() {
+        return getInputValue(emailInput);
+    }
+
+    public void setEmail(String email) {
+        setInputValue(emailInput, email);
+    }
+
+    public String getFirstName() {
+        return getInputValue(firstNameInput);
+    }
+
+    public void setFirstName(String firstName) {
+        setInputValue(firstNameInput, firstName);
+    }
+
+    public String getLastName() {
+        return getInputValue(lastNameInput);
+    }
+
+    public void setLastName(String lastname) {
+        setInputValue(lastNameInput, lastname);
+    }
+
+    public boolean isEnabled() {
+        return userEnabledSwitch.isOn();
+    }
+
+    public void setEnabled(boolean enabled) {
+        userEnabledSwitch.setOn(enabled);
+    }
+
+    public void unlockUser() {
+        unlockUserButton.click();
+    }
+
+    public boolean isEmailVerified() {
+        return emailVerifiedSwitch.isOn();
+    }
+
+    public void setEmailVerified(boolean emailVerified) {
+        emailVerifiedSwitch.setOn(emailVerified);
+    }
+
+    public void addRequiredAction(String requiredAction) {
+        requiredUserActionsInput.click();
+        requiredUserActionsSelect.selectByVisibleText(requiredAction);
+    }
+
+    public void setRequiredActions(List<String> requiredActions) {
+        for (WebElement e : removeRequiredActionsList) {
+            e.click();
+        }
+        if (requiredActions != null && !requiredActions.isEmpty()) {
+            for (String action : requiredActions) {
+                addRequiredAction(action);
+            }
+        }
+    }
+
+    public void setValues(UserRepresentation user) {
+        waitAjaxForElement(usernameInput);
+        setUsername(user.getUsername());
+        setEmail(user.getEmail());
+        setFirstName(user.getFirstName());
+        setLastName(user.getLastName());
+        setEnabled(user.isEnabled());
+        setEmailVerified(user.isEmailVerified());
+        setRequiredActions(user.getRequiredActions());
+    }
+
+    // TODO Contact Information section
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserConsents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserConsents.java
new file mode 100644
index 0000000..6525763
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserConsents.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.users;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserConsents extends User {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/consents";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java
new file mode 100644
index 0000000..830d789
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import static org.keycloak.testsuite.page.Form.setInputValue;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserCredentials extends User {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/user-credentials";
+    }
+
+    @FindBy(id = "password")
+    private WebElement newPasswordInput;
+
+    @FindBy(id = "confirmPassword")
+    private WebElement confirmPasswordInput;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='temporaryPassword']]")
+    private OnOffSwitch temporaryOnOffSwitch;
+
+    @FindBy(xpath = ".//button[contains(@data-ng-click, 'resetPassword')]")
+    private WebElement resetPasswordButton;
+
+    public void setNewPassword(String newPassword) {
+        setInputValue(newPasswordInput, newPassword);
+    }
+
+    public void setConfirmPassword(String confirmPassword) {
+        setInputValue(confirmPasswordInput, confirmPassword);
+    }
+
+    public void setTemporary(boolean temporary) {
+        temporaryOnOffSwitch.setOn(temporary);
+    }
+
+    public void clickResetPasswordAndConfirm() {
+        resetPasswordButton.click();
+        modalDialog.ok();
+    }
+    
+    public void resetPassword(String newPassword) {
+        resetPassword(newPassword, newPassword);
+    }
+    public void resetPassword(String newPassword, String confirmPassword) {
+        setNewPassword(newPassword);
+        setConfirmPassword(confirmPassword);
+        clickResetPasswordAndConfirm();
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java
new file mode 100644
index 0000000..3a05b68
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java
@@ -0,0 +1,28 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.admin.client.resource.RoleMappingResource;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserRoleMappings extends User {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "role-mappings";
+    }
+
+    @Page
+    private UserRoleMappingsForm form;
+
+    public UserRoleMappingsForm form() {
+        return form;
+    }
+    
+    public RoleMappingResource roleMappingResource() {
+        return userResource().roles();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappingsForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappingsForm.java
new file mode 100644
index 0000000..2629017
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappingsForm.java
@@ -0,0 +1,46 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.roles.RoleCompositeRoles;
+
+/**
+ * Created by fkiss.
+ */
+public class UserRoleMappingsForm extends RoleCompositeRoles {
+
+    @FindBy(id = "realm-composite")
+    private Select effectiveRolesSelect;
+
+    @FindBy(id = "client-composite")
+    private Select effectiveClientRolesSelect;
+
+    public boolean isEffectiveRealmRolesComplete(RoleRepresentation... roles) {
+        return isEffectiveRolesComplete(effectiveRolesSelect, roles);
+    }
+
+    public boolean isEffectiveClientRolesComplete(RoleRepresentation... roles) {
+        return isEffectiveRolesComplete(effectiveClientRolesSelect, roles);
+    }
+
+    private boolean isEffectiveRolesComplete(Select select, RoleRepresentation... roles) {
+        List<String> roleNames = new ArrayList<>();
+        for (RoleRepresentation role : roles) {
+            roleNames.add(role.getName());
+        }
+        for (WebElement role : select.getOptions()) {
+            roleNames.contains(role.getText());
+            roleNames.remove(role.getText());
+        }
+        log.info(Arrays.toString(roles));
+        log.info(roleNames);
+        return roleNames.isEmpty();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/Users.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/Users.java
new file mode 100644
index 0000000..3b1d730
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/Users.java
@@ -0,0 +1,142 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.page.users;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import static org.openqa.selenium.By.*;
+
+/**
+ *
+ * @author Filip Kiss
+ * @author tkyjovsk
+ */
+public class Users extends AdminConsoleRealm {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/users";
+    }
+
+    public static final String VIEW_ALL_USERS = "View all users";
+    public static final String UNLOCK_USERS = "Unlock Users";
+    public static final String ADD_USER = "Add User";
+
+    public static final String EDIT = "Edit";
+    public static final String IMPERSONATE = "Impersonate";
+    public static final String DELETE = "Delete";
+
+    @FindBy(xpath = "//div[./h1[text()='Users']]/table")
+    private UsersTable table;
+
+    public UsersTable table() {
+        return table;
+    }
+
+    public class UsersTable extends DataTable {
+
+        public List<UserRepresentation> searchUsers(String searchPattern) {
+            search(searchPattern);
+            return getUsersFromTableRows();
+        }
+
+        public void viewAllUsers() {
+            clickHeaderButton(VIEW_ALL_USERS);
+        }
+
+        public void unlockUsers() {
+            clickHeaderButton(UNLOCK_USERS);
+        }
+
+        public void clickUser(String username) {
+            waitAjaxForElement(body());
+            body().findElement(linkText(username)).click();
+        }
+
+        public void editUser(String username) {
+            clickRowActionButton(getRowByLinkText(username), EDIT);
+        }
+
+        public void impersonateUser(String username) {
+            clickRowActionButton(getRowByLinkText(username), IMPERSONATE);
+        }
+
+        public void deleteUser(String username) {
+            clickRowActionButton(getRowByLinkText(username), DELETE);
+            modalDialog.confirmDeletion();
+        }
+
+        public void addUser() {
+            clickHeaderLink(ADD_USER);
+        }
+
+        public UserRepresentation findUser(String searchPattern) {
+            List<UserRepresentation> users = searchUsers(searchPattern);
+            if (users.isEmpty()) {
+                return null;
+            } else {
+                assert 1 == users.size();
+                return users.get(0);
+            }
+        }
+
+        public UserRepresentation getUserFromTableRow(WebElement row) {
+            UserRepresentation user = null;
+            List<WebElement> tds = row.findElements(tagName("td"));
+            if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
+                user = new UserRepresentation();
+                user.setUsername(tds.get(0).getText());
+                user.setLastName(tds.get(1).getText());
+                user.setFirstName(tds.get(2).getText());
+                user.setEmail(tds.get(3).getText());
+            }
+            return user;
+        }
+
+        public List<UserRepresentation> getUsersFromTableRows() {
+            List<UserRepresentation> users = new ArrayList<>();
+            List<WebElement> rows = rows();
+//            if (rows.size() > 1) {
+                for (WebElement rowElement : rows) {
+                    if (rowElement.isDisplayed()) {
+                        UserRepresentation user = getUserFromTableRow(rowElement);
+                        if (user != null) {
+                            users.add(user);
+                        }
+                    }
+                }
+//            }
+            return users;
+        }
+
+    }
+    
+    public UsersResource usersResource() {
+        return realmResource().users();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserSessions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserSessions.java
new file mode 100644
index 0000000..bfe9ac5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserSessions.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.users;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserSessions extends User {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/sessions";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java
new file mode 100644
index 0000000..a06666c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java
@@ -0,0 +1,83 @@
+package org.keycloak.testsuite.page;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.openqa.selenium.WebDriver;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractPage {
+
+    protected final Logger log = Logger.getLogger(this.getClass());
+
+    private final Map<String, Object> uriParameters = new HashMap<>();
+
+    @Drone
+    protected WebDriver driver;
+
+    private UriBuilder builder;
+
+    public WebDriver getDriver() {
+        return driver;
+    }
+
+    public abstract UriBuilder createUriBuilder();
+
+    public String getUriFragment() {
+        return "";
+    }
+
+    /**
+     *
+     * @return Instance of UriBuilder that can build URIs for a concrete page.
+     */
+    public UriBuilder getUriBuilder() {
+        if (builder == null) {
+            builder = createUriBuilder();
+            String fragment = getUriFragment();
+            if (fragment != null && !fragment.isEmpty()) {
+                builder.fragment(fragment);
+            }
+        }
+        return builder;
+    }
+
+    public AbstractPage setUriParameter(String name, Object value) {
+        uriParameters.put(name, value);
+        return this;
+    }
+
+    public Object getUriParameter(String name) {
+        return uriParameters.get(name);
+    }
+
+    public URI buildUri() {
+        return getUriBuilder().buildFromMap(uriParameters);
+    }
+
+    @Override
+    public String toString() {
+        return buildUri().toASCIIString();
+    }
+
+    public void navigateTo() {
+        String uri = buildUri().toASCIIString();
+        log.debug("current URL:  " + driver.getCurrentUrl());
+        log.info("navigating to " + uri);
+        driver.navigate().to(uri);
+        pause(300); // this is needed for FF for some reason
+        log.info("current URL:  " + driver.getCurrentUrl());
+    }
+
+    public boolean isCurrent() {
+        return driver.getCurrentUrl().equals(toString());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java
new file mode 100644
index 0000000..b85c75a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.page;
+
+import java.net.URISyntaxException;
+import java.net.URL;
+import javax.ws.rs.core.UriBuilder;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractPageWithInjectedUrl extends AbstractPage {
+
+    public abstract URL getInjectedUrl();
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        try {
+            return UriBuilder.fromUri(getInjectedUrl().toURI());
+        } catch (URISyntaxException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java
new file mode 100644
index 0000000..eee8a21
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.page;
+
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import static org.jboss.arquillian.graphene.Graphene.guardAjax;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Form {
+
+    protected final Logger log = Logger.getLogger(this.getClass());
+    
+    @Drone
+    protected WebDriver driver;
+
+    public static final String ACTIVE_DIV_XPATH = ".//div[not(contains(@class,'ng-hide'))]";
+
+    @FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Save']")
+    private WebElement save;
+    @FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Cancel']")
+    private WebElement cancel;
+
+    public void save() {
+//        guardAjax(save).click();
+        save.click();
+    }
+
+    public void cancel() {
+        guardAjax(cancel).click();
+    }
+
+    public static String getInputValue(WebElement input) {
+        waitAjaxForElement(input);
+        return input.getAttribute(VALUE);
+    }
+
+    public static final String VALUE = "value";
+
+    public static void setInputValue(WebElement input, String value) {
+        waitAjaxForElement(input);
+        if (input.isEnabled()) {
+            input.clear();
+            if (value != null) {
+                input.sendKeys(value);
+            }
+        } else {
+            // TODO log warning
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/servlet/ApplicationServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/servlet/ApplicationServlet.java
new file mode 100644
index 0000000..2898773
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/servlet/ApplicationServlet.java
@@ -0,0 +1,61 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.servlet;
+
+import org.keycloak.services.resources.RealmsResource;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ApplicationServlet extends HttpServlet {
+
+    private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String title;
+        if (req.getRequestURI().endsWith("auth")) {
+            title = "AUTH_RESPONSE";
+        } else if (req.getRequestURI().endsWith("logout")) {
+            title = "LOGOUT_REQUEST";
+        } else {
+            title = "APP_REQUEST";
+        }
+
+        PrintWriter pw = resp.getWriter();
+        pw.printf("<html><head><title>%s</title></head><body>", title);
+        UriBuilder base = UriBuilder.fromUri("http://localhost:8081/auth");
+        pw.printf(LINK, RealmsResource.accountUrl(base).build("test"), "account", "account");
+
+        pw.print("</body></html>");
+        pw.flush();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
new file mode 100644
index 0000000..9ff2bcf
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
@@ -0,0 +1,43 @@
+package org.keycloak.testsuite.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class IOUtil {
+
+    public static <T> T loadJson(InputStream is, Class<T> type) {
+        try {
+            return JsonSerialization.readValue(is, type);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to load json.", e);
+        }
+    }
+
+    public static RealmRepresentation loadRealm(String realmConfig) {
+        return loadRealm(IOUtil.class.getResourceAsStream(realmConfig));
+    }
+
+    public static RealmRepresentation loadRealm(File realmFile) {
+        try {
+            return loadRealm(new FileInputStream(realmFile));
+        } catch (FileNotFoundException ex) {
+            throw new IllegalStateException("Test realm file not found: " + realmFile);
+        }
+    }
+
+    public static RealmRepresentation loadRealm(InputStream is) {
+        RealmRepresentation realm = loadJson(is, RealmRepresentation.class);
+        System.out.println("Loaded realm " + realm.getRealm());
+        return realm;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPTestConfiguration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPTestConfiguration.java
new file mode 100644
index 0000000..9d1d19e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPTestConfiguration.java
@@ -0,0 +1,128 @@
+package org.keycloak.testsuite.util;
+
+import org.jboss.logging.Logger;
+import org.keycloak.constants.KerberosConstants;
+import org.keycloak.models.LDAPConstants;
+import org.keycloak.models.UserFederationProvider;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class LDAPTestConfiguration {
+
+    private static final Logger log = Logger.getLogger(LDAPTestConfiguration.class);
+
+    private String connectionPropertiesLocation;
+    private boolean startEmbeddedLdapLerver = true;
+    private Map<String, String> config;
+
+    protected static final Map<String, String> PROP_MAPPINGS = new HashMap<String, String>();
+    protected static final Map<String, String> DEFAULT_VALUES = new HashMap<String, String>();
+
+    static {
+        PROP_MAPPINGS.put(LDAPConstants.CONNECTION_URL, "idm.test.ldap.connection.url");
+        PROP_MAPPINGS.put(LDAPConstants.BASE_DN, "idm.test.ldap.base.dn");
+        PROP_MAPPINGS.put(LDAPConstants.USERS_DN, "idm.test.ldap.user.dn.suffix");
+        PROP_MAPPINGS.put(LDAPConstants.BIND_DN, "idm.test.ldap.bind.dn");
+        PROP_MAPPINGS.put(LDAPConstants.BIND_CREDENTIAL, "idm.test.ldap.bind.credential");
+        PROP_MAPPINGS.put(LDAPConstants.VENDOR, "idm.test.ldap.vendor");
+        PROP_MAPPINGS.put(LDAPConstants.CONNECTION_POOLING, "idm.test.ldap.connection.pooling");
+        PROP_MAPPINGS.put(LDAPConstants.PAGINATION, "idm.test.ldap.pagination");
+        PROP_MAPPINGS.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, "idm.test.ldap.batch.size.for.sync");
+        PROP_MAPPINGS.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, "idm.test.ldap.username.ldap.attribute");
+        PROP_MAPPINGS.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, "idm.test.ldap.rdn.ldap.attribute");
+        PROP_MAPPINGS.put(LDAPConstants.USER_OBJECT_CLASSES, "idm.test.ldap.user.object.classes");
+        PROP_MAPPINGS.put(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE, "idm.test.ldap.user.account.controls.after.password.update");
+        PROP_MAPPINGS.put(LDAPConstants.EDIT_MODE, "idm.test.ldap.edit.mode");
+
+        PROP_MAPPINGS.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "idm.test.kerberos.allow.kerberos.authentication");
+        PROP_MAPPINGS.put(KerberosConstants.KERBEROS_REALM, "idm.test.kerberos.realm");
+        PROP_MAPPINGS.put(KerberosConstants.SERVER_PRINCIPAL, "idm.test.kerberos.server.principal");
+        PROP_MAPPINGS.put(KerberosConstants.KEYTAB, "idm.test.kerberos.keytab");
+        PROP_MAPPINGS.put(KerberosConstants.DEBUG, "idm.test.kerberos.debug");
+        PROP_MAPPINGS.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "idm.test.kerberos.allow.password.authentication");
+        PROP_MAPPINGS.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "idm.test.kerberos.update.profile.first.login");
+        PROP_MAPPINGS.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "idm.test.kerberos.use.kerberos.for.password.authentication");
+
+        DEFAULT_VALUES.put(LDAPConstants.CONNECTION_URL, "ldap://localhost:10389");
+        DEFAULT_VALUES.put(LDAPConstants.BASE_DN, "dc=keycloak,dc=org");
+        DEFAULT_VALUES.put(LDAPConstants.USERS_DN, "ou=People,dc=keycloak,dc=org");
+        DEFAULT_VALUES.put(LDAPConstants.BIND_DN, "uid=admin,ou=system");
+        DEFAULT_VALUES.put(LDAPConstants.BIND_CREDENTIAL, "secret");
+        DEFAULT_VALUES.put(LDAPConstants.VENDOR, LDAPConstants.VENDOR_OTHER);
+        DEFAULT_VALUES.put(LDAPConstants.CONNECTION_POOLING, "true");
+        DEFAULT_VALUES.put(LDAPConstants.PAGINATION, "true");
+        DEFAULT_VALUES.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, String.valueOf(LDAPConstants.DEFAULT_BATCH_SIZE_FOR_SYNC));
+        DEFAULT_VALUES.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, null);
+        DEFAULT_VALUES.put(LDAPConstants.USER_OBJECT_CLASSES, null);
+        DEFAULT_VALUES.put(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE, "false");
+        DEFAULT_VALUES.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.READ_ONLY.toString());
+
+        DEFAULT_VALUES.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "false");
+        DEFAULT_VALUES.put(KerberosConstants.KERBEROS_REALM, "KEYCLOAK.ORG");
+        DEFAULT_VALUES.put(KerberosConstants.SERVER_PRINCIPAL, "HTTP/localhost@KEYCLOAK.ORG");
+        URL keytabUrl = LDAPTestConfiguration.class.getResource("/kerberos/http.keytab");
+        String keyTabPath = new File(keytabUrl.getFile()).getAbsolutePath();
+        DEFAULT_VALUES.put(KerberosConstants.KEYTAB, keyTabPath);
+        DEFAULT_VALUES.put(KerberosConstants.DEBUG, "true");
+        DEFAULT_VALUES.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "true");
+        DEFAULT_VALUES.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
+        DEFAULT_VALUES.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "false");
+    }
+
+    public static LDAPTestConfiguration readConfiguration(String connectionPropertiesLocation) {
+        LDAPTestConfiguration ldapTestConfiguration = new LDAPTestConfiguration();
+        ldapTestConfiguration.setConnectionPropertiesLocation(connectionPropertiesLocation);
+        ldapTestConfiguration.loadConnectionProperties();
+        return ldapTestConfiguration;
+    }
+
+    protected void loadConnectionProperties() {
+        Properties p = new Properties();
+        try {
+            log.info("Reading LDAP configuration from: " + connectionPropertiesLocation);
+            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(connectionPropertiesLocation);
+            p.load(is);
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        config = new HashMap<String, String>();
+        for (Map.Entry<String, String> property : PROP_MAPPINGS.entrySet()) {
+            String propertyName = property.getKey();
+            String configName = property.getValue();
+
+            String value = (String) p.get(configName);
+            if (value == null) {
+                value = DEFAULT_VALUES.get(propertyName);
+            }
+
+            config.put(propertyName, value);
+        }
+
+        startEmbeddedLdapLerver = Boolean.parseBoolean(p.getProperty("idm.test.ldap.start.embedded.ldap.server", "true"));
+        log.info("Start embedded server: " + startEmbeddedLdapLerver);
+        log.info("Read config: " + config);
+    }
+
+    public Map<String,String> getLDAPConfig() {
+        return config;
+    }
+
+    public void setConnectionPropertiesLocation(String connectionPropertiesLocation) {
+        this.connectionPropertiesLocation = connectionPropertiesLocation;
+    }
+
+    public boolean isStartEmbeddedLdapLerver() {
+        return startEmbeddedLdapLerver;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java
new file mode 100644
index 0000000..ba5790d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java
@@ -0,0 +1,11 @@
+package org.keycloak.testsuite.util;
+
+/**
+ *
+ * @author vramik
+ */
+public class MailServerConfiguration {
+    public static final String FROM = "server@mail.test";
+    public static final String HOST = "localhost";
+    public static final String PORT = "3025";
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Timer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Timer.java
new file mode 100644
index 0000000..0ce7eda
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Timer.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.util;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Timer {
+
+    private static Long time;
+
+    private static final Map<String, List<Long>> stats = new HashMap<>();
+
+    public static void time() {
+        time = new Date().getTime();
+    }
+
+    public static void time(String operation) {
+        if (time == null) {
+            System.out.println(MessageFormat.format("Starting timer for operation {0}", operation));
+            time();
+        } else {
+            long timeOrig = time;
+            time();
+            logOperation(operation, time - timeOrig);
+            System.out.println(MessageFormat.format("Operation {0} took {1} ms", operation, time - timeOrig));
+        }
+    }
+
+    private static void logOperation(String operation, long delta) {
+        if (!stats.containsKey(operation)) {
+            stats.put(operation, new ArrayList<Long>());
+        }
+        stats.get(operation).add(delta);
+    }
+
+    public static void printStats() {
+        if (!stats.isEmpty()) {
+            System.out.println("OPERATION STATS:");
+        }
+        for (String op : stats.keySet()) {
+            long sum = 0;
+            for (Long t : stats.get(op)) {
+                sum += t;
+            }
+            System.out.println(MessageFormat.format("Operation {0} average time: {1,number,#} ms", op, sum / stats.get(op).size()));
+        }
+        stats.clear();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/testsuite/integration-arquillian/tests/base/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
new file mode 100644
index 0000000..88c25fa
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
@@ -0,0 +1,3 @@
+org.keycloak.testsuite.arquillian.KeycloakArquillianExtension
+!org.jboss.arquillian.container.impl.ContainerExtension
+org.keycloak.testsuite.arquillian.containers.MultipleContainersExtension
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java
new file mode 100644
index 0000000..98aa62e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java
@@ -0,0 +1,104 @@
+package org.keycloak.testsuite;
+
+import java.text.MessageFormat;
+import java.util.List;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.keycloak.admin.client.resource.RealmResource;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.login.OIDCLogin;
+import org.keycloak.testsuite.console.page.fragment.FlashMessage;
+import org.openqa.selenium.Cookie;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractAuthTest extends AbstractKeycloakTest {
+
+    @Page
+    protected AuthRealm testRealmPage;
+    @Page
+    protected OIDCLogin testRealmLoginPage;
+
+    protected UserRepresentation testUser;
+
+    @FindByJQuery(".alert")
+    protected FlashMessage flashMessage;
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation testRealmRep = new RealmRepresentation();
+        testRealmRep.setRealm(TEST);
+        testRealmRep.setEnabled(true);
+        testRealms.add(testRealmRep);
+    }
+
+    @Before
+    public void beforeAuthTest() {
+        testRealmLoginPage.setAuthRealm(testRealmPage);
+
+        testUser = createUserRepresentation("test", "test@email.test", "test", "user", true);
+        setPasswordFor(testUser, PASSWORD);
+
+        deleteAllCookiesForTestRealm();
+    }
+    
+    public void createTestUserWithAdminClient() {
+        log.debug("creating test user");
+        String id = createUserAndResetPasswordWithAdminClient(testRealmResource(), testUser, PASSWORD);
+        testUser.setId(id);
+    }
+
+    public static UserRepresentation createUserRepresentation(String username, String email, String firstName, String lastName, boolean enabled) {
+        UserRepresentation user = new UserRepresentation();
+        user.setUsername(username);
+        user.setEmail(email);
+        user.setFirstName(firstName);
+        user.setLastName(lastName);
+        user.setEnabled(enabled);
+        return user;
+    }
+
+    public void deleteAllCookiesForTestRealm() {
+        testRealmPage.navigateTo();
+        log.debug("deleting cookies in test realm");
+        driver.manage().deleteAllCookies();
+    }
+
+    public void listCookies() {
+        log.info("LIST OF COOKIES: ");
+        for (Cookie c : driver.manage().getCookies()) {
+            log.info(MessageFormat.format(" {1} {2} {0}",
+                    c.getName(), c.getDomain(), c.getPath(), c.getValue()));
+        }
+    }
+
+    public void assertFlashMessageSuccess() {
+        flashMessage.waitUntilPresent();
+        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+    }
+
+    public void assertFlashMessageDanger() {
+        flashMessage.waitUntilPresent();
+        assertTrue(flashMessage.getText(), flashMessage.isDanger());
+    }
+
+    public void assertFlashMessageError() {
+        flashMessage.waitUntilPresent();
+        assertTrue(flashMessage.getText(), flashMessage.isError());
+    }
+
+    public RealmResource testRealmResource() {
+        return adminClient.realm(testRealmPage.getAuthRealm());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
new file mode 100644
index 0000000..3399115
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -0,0 +1,176 @@
+package org.keycloak.testsuite;
+
+import org.keycloak.testsuite.arquillian.TestContext;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import javax.ws.rs.NotFoundException;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.logging.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import org.keycloak.testsuite.arquillian.SuiteContext;
+import org.openqa.selenium.WebDriver;
+import org.keycloak.testsuite.auth.page.AuthServer;
+import org.keycloak.testsuite.auth.page.AuthServerContextRoot;
+import static org.keycloak.testsuite.util.URLAssert.*;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
+import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
+import org.keycloak.testsuite.auth.page.account.Account;
+import org.keycloak.testsuite.auth.page.login.OIDCLogin;
+import org.keycloak.testsuite.auth.page.login.UpdatePassword;
+import org.keycloak.testsuite.util.Timer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@RunWith(Arquillian.class)
+@RunAsClient
+public abstract class AbstractKeycloakTest {
+
+    protected Logger log = Logger.getLogger(this.getClass());
+
+    @ArquillianResource
+    protected SuiteContext suiteContext;
+
+    @ArquillianResource
+    protected TestContext testContext;
+    
+    @ArquillianResource
+    protected Keycloak adminClient;
+
+    protected List<RealmRepresentation> testRealmReps;
+
+    @Drone
+    protected WebDriver driver;
+
+    @Page
+    protected AuthServerContextRoot authServerContextRootPage;
+    @Page
+    protected AuthServer authServerPage;
+
+    @Page
+    protected AuthRealm masterRealmPage;
+
+    @Page
+    protected Account accountPage;
+    @Page
+    protected OIDCLogin loginPage;
+    @Page
+    protected UpdatePassword updatePasswordPage;
+
+    protected UserRepresentation adminUser;
+
+    @Before
+    public void beforeAbstractKeycloakTest() {
+        adminUser = createAdminUserRepresentation();
+
+        setDefaultPageUriParameters();
+
+        driverSettings();
+
+        if (!suiteContext.isAdminPasswordUpdated()) {
+            updateMasterAdminPassword();
+            suiteContext.setAdminPasswordUpdated(true);
+        }
+
+        importTestRealms();
+    }
+
+    @After
+    public void afterAbstractKeycloakTest() {
+//        removeTestRealms(); // keeping test realms after test to be able to inspect failures, instead deleting existing realms before import
+//        keycloak.close(); // keeping admin connection open
+        Timer.printStats();
+    }
+
+    private void updateMasterAdminPassword() {
+        accountPage.navigateTo();
+        loginPage.form().login(ADMIN, ADMIN);
+        updatePasswordPage.updatePasswords(ADMIN, ADMIN);
+        assertCurrentUrlStartsWith(accountPage);
+        deleteAllCookiesForMasterRealm();
+    }
+
+    public void deleteAllCookiesForMasterRealm() {
+        masterRealmPage.navigateTo();
+        log.debug("deleting cookies in master realm");
+        driver.manage().deleteAllCookies();
+    }
+
+    protected void driverSettings() {
+        driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
+        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
+        driver.manage().timeouts().setScriptTimeout(3, TimeUnit.SECONDS);
+        driver.manage().window().maximize();
+    }
+
+    public void setDefaultPageUriParameters() {
+        masterRealmPage.setAuthRealm(MASTER);
+        loginPage.setAuthRealm(MASTER);
+    }
+
+    public abstract void addTestRealms(List<RealmRepresentation> testRealms);
+
+    private void addTestRealms() {
+        log.debug("loading test realms");
+        if (testRealmReps == null) {
+            testRealmReps = new ArrayList<>();
+        }
+        if (testRealmReps.isEmpty()) {
+            addTestRealms(testRealmReps);
+        }
+    }
+
+    public void importTestRealms() {
+        addTestRealms();
+        log.info("importing test realms");
+        for (RealmRepresentation testRealm : testRealmReps) {
+            importRealm(testRealm);
+        }
+    }
+
+    public void removeTestRealms() {
+        log.info("removing test realms");
+        for (RealmRepresentation testRealm : testRealmReps) {
+            removeRealm(testRealm);
+        }
+    }
+
+    private UserRepresentation createAdminUserRepresentation() {
+        UserRepresentation adminUserRep = new UserRepresentation();
+        adminUserRep.setUsername(ADMIN);
+        setPasswordFor(adminUserRep, ADMIN);
+        return adminUserRep;
+    }
+
+    public void importRealm(RealmRepresentation realm) {
+        log.debug("importing realm: " + realm.getRealm());
+        try { // TODO - figure out a way how to do this without try-catch
+            RealmResource realmResource = adminClient.realms().realm(realm.getRealm());
+            RealmRepresentation rRep = realmResource.toRepresentation();
+            log.debug("realm already exists on server, re-importing");
+            realmResource.remove();
+        } catch (NotFoundException nfe) {
+            // expected when realm does not exist
+        }
+        adminClient.realms().create(realm);
+    }
+
+    public void removeRealm(RealmRepresentation realm) {
+        adminClient.realms().realm(realm.getRealm()).remove();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AbstractAccountManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AbstractAccountManagementTest.java
new file mode 100644
index 0000000..6a7a4c1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AbstractAccountManagementTest.java
@@ -0,0 +1,31 @@
+package org.keycloak.testsuite.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.testsuite.AbstractAuthTest;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.account.AccountManagement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractAccountManagementTest extends AbstractAuthTest {
+
+    @Page
+    protected AccountManagement testRealmAccountManagementPage;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(TEST);
+        testRealmAccountManagementPage.setAuthRealm(TEST);
+    }
+
+    @Before
+    public void beforeAbstractAccountTest() {
+        // make user test user exists in test realm
+        createTestUserWithAdminClient();
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
new file mode 100644
index 0000000..e509276
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -0,0 +1,80 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.After;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.keycloak.testsuite.auth.page.account.Account;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class AccountTest extends AbstractAccountManagementTest {
+
+    private static final String UPDATED_EMAIL = "new-name@email.test";
+    private static final String NEW_FIRST_NAME = "John";
+    private static final String NEW_LAST_NAME = "Smith";
+
+    @Page
+    private Account testRealmAccountPage;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmAccountPage.setAuthRealm(testRealmPage);
+    }
+    
+    @Before
+    public void beforeAccountTest() {
+        testRealmAccountManagementPage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+    }
+
+    @After
+    public void afterAccountTest() {
+        testRealmAccountManagementPage.navigateTo();
+        testRealmAccountManagementPage.signOut();
+    }
+
+    @Test
+    public void editAccount() {
+        testRealmAccountManagementPage.account();
+        assertEquals(testRealmAccountPage.getUsername(), testUser.getUsername());
+        
+        testRealmAccountPage.setEmail(UPDATED_EMAIL);
+        testRealmAccountPage.setFirstName(NEW_FIRST_NAME);
+        testRealmAccountPage.setLastName(NEW_LAST_NAME);
+        testRealmAccountPage.save();
+        assertFlashMessageSuccess();
+
+        testRealmAccountManagementPage.signOut();
+        testRealmLoginPage.form().login(testUser);
+        
+        testRealmAccountManagementPage.account();
+        assertEquals(testRealmAccountPage.getEmail(), UPDATED_EMAIL);
+        assertEquals(testRealmAccountPage.getFirstName(), NEW_FIRST_NAME);
+        assertEquals(testRealmAccountPage.getLastName(), NEW_LAST_NAME);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ChangePasswordTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ChangePasswordTest.java
new file mode 100644
index 0000000..5787903
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ChangePasswordTest.java
@@ -0,0 +1,67 @@
+package org.keycloak.testsuite.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.testsuite.auth.page.account.ChangePassword;
+import static org.keycloak.testsuite.admin.Users.getPasswordOf;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ChangePasswordTest extends AbstractAccountManagementTest {
+
+    private static final String NEW_PASSWORD = "newpassword";
+    private static final String WRONG_PASSWORD = "wrongpassword";
+
+    @Page
+    private ChangePassword testRealmChangePasswordPage;
+
+    private String correctPassword;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmChangePasswordPage.setAuthRealm(testRealmPage);
+    }
+
+    @Before
+    public void beforeChangePasswordTest() {
+        correctPassword = getPasswordOf(testUser);
+        testRealmAccountManagementPage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+        testRealmAccountManagementPage.password();
+    }
+
+    @Test
+    public void invalidChangeAttempts() {
+        testRealmChangePasswordPage.save();
+        assertFlashMessageError();
+
+        testRealmChangePasswordPage.changePasswords(WRONG_PASSWORD, NEW_PASSWORD, NEW_PASSWORD);
+        assertFlashMessageError();
+
+        testRealmChangePasswordPage.changePasswords(correctPassword, NEW_PASSWORD, NEW_PASSWORD + "-mismatch");
+        assertFlashMessageError();
+    }
+
+    @Test
+    public void successfulChangeAttempts() {
+        // change password successfully
+        testRealmChangePasswordPage.changePasswords(correctPassword, NEW_PASSWORD, NEW_PASSWORD);
+        assertFlashMessageSuccess();
+
+        // login using new password
+        testRealmAccountManagementPage.signOut();
+        testRealmLoginPage.form().login(testUser.getUsername(), NEW_PASSWORD);
+        assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+
+        // change password back
+        testRealmAccountManagementPage.password();
+        testRealmChangePasswordPage.changePasswords(NEW_PASSWORD, correctPassword, correctPassword);
+        assertFlashMessageSuccess();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/RegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/RegistrationTest.java
new file mode 100644
index 0000000..5297038
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/RegistrationTest.java
@@ -0,0 +1,132 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+import org.keycloak.testsuite.auth.page.login.Registration;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername;
+import static org.keycloak.testsuite.admin.Users.getPasswordOf;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class RegistrationTest extends AbstractAccountManagementTest {
+
+    @Page
+    private Registration testRealmRegistrationPage;
+
+    private UserRepresentation newUser;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmRegistrationPage.setAuthRealm(testRealmPage);
+    }
+
+    @Before
+    public void beforeUserRegistration() {
+        // enable user registration in test realm
+        RealmRepresentation testRealmRep = testRealmResource().toRepresentation();
+        testRealmRep.setRegistrationAllowed(true);
+        testRealmResource().update(testRealmRep);
+
+        newUser = createUserRepresentation("new_user", "new_user@email.test", "new", "user", true);
+        setPasswordFor(newUser, PASSWORD);
+
+        testRealmAccountManagementPage.navigateTo();
+        testRealmLoginPage.form().register();
+    }
+
+    public void assertUserExistsWithAdminClient(UserRepresentation user) {
+        assertNotNull(findUserByUsername(testRealmResource(), user.getUsername()));
+    }
+
+    public void assertUserDoesntExistWithAdminClient(UserRepresentation user) {
+        assertNull(findUserByUsername(testRealmResource(), user.getUsername()));
+    }
+
+    public void assertMessageAttributeMissing(String attributeName) {
+        assertTrue(testRealmRegistrationPage.getFeedbackText()
+                .contains("Please specify " + attributeName + "."));
+    }
+
+    @Test
+    public void successfulRegistration() {
+        testRealmRegistrationPage.register(newUser);
+        assertUserExistsWithAdminClient(newUser);
+    }
+
+    @Test
+    public void invalidEmail() {
+        newUser.setEmail("invalid.email.value");
+        testRealmRegistrationPage.register(newUser);
+        assertTrue(testRealmRegistrationPage.getFeedbackText()
+                .equals("Invalid email address."));
+        assertUserDoesntExistWithAdminClient(newUser);
+    }
+
+    @Test
+    public void emptyAttributes() {
+        UserRepresentation newUserEmpty = new UserRepresentation(); // empty user attributes
+
+        testRealmRegistrationPage.register(newUserEmpty);
+        assertMessageAttributeMissing("username");
+
+        newUserEmpty.setUsername(newUser.getUsername());
+        testRealmRegistrationPage.register(newUserEmpty);
+        assertMessageAttributeMissing("first name");
+
+        newUserEmpty.setFirstName(newUser.getFirstName());
+        testRealmRegistrationPage.register(newUserEmpty);
+        assertMessageAttributeMissing("last name");
+
+        newUserEmpty.setLastName(newUser.getLastName());
+        testRealmRegistrationPage.register(newUserEmpty);
+        assertMessageAttributeMissing("email");
+
+        newUserEmpty.setEmail(newUser.getEmail());
+        testRealmRegistrationPage.register(newUserEmpty);
+        assertMessageAttributeMissing("password");
+
+        setPasswordFor(newUserEmpty, getPasswordOf(newUser));
+        testRealmRegistrationPage.register(newUser);
+        assertUserExistsWithAdminClient(newUserEmpty);
+    }
+
+    @Test
+    public void notMatchingPasswords() {
+        testRealmRegistrationPage.setValues(newUser, "not-matching-password");
+        testRealmRegistrationPage.submit();
+        assertTrue(testRealmRegistrationPage.getFeedbackText()
+                .equals("Password confirmation doesn't match."));
+
+        testRealmRegistrationPage.register(newUser);
+        assertUserExistsWithAdminClient(newUser);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResetCredentialsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResetCredentialsTest.java
new file mode 100644
index 0000000..95bff41
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResetCredentialsTest.java
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.AfterClass;
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.auth.page.login.ResetCredentials;
+import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl;
+import org.keycloak.testsuite.util.MailServer;
+import org.keycloak.testsuite.util.MailServerConfiguration;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+
+/**
+ *
+ * @author vramik
+ */
+public class ResetCredentialsTest extends AbstractAccountManagementTest {
+
+    @Page
+    private ResetCredentials testRealmResetCredentialsPage;
+    
+    private static boolean init = false;
+    
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmResetCredentialsPage.setAuthRealm(testRealmPage);
+    }
+
+    @Before
+    public void beforeResetCredentials() {
+        // enable reset credentials and configure smpt server in test realm
+        RealmRepresentation testRealmRep = testRealmResource().toRepresentation();
+        testRealmRep.setSmtpServer(suiteContext.getSmtpServer());
+        testRealmRep.setResetPasswordAllowed(true);
+        testRealmResource().update(testRealmRep);
+
+        if (!init) {
+            init = true;
+            MailServer.start();
+            MailServer.createEmailAccount(testUser.getEmail(), "password");
+        }
+        
+        testRealmAccountManagementPage.navigateTo();
+        testRealmLoginPage.form().forgotPassword();
+    }
+    
+    @AfterClass
+    public static void afterClass() {
+        MailServer.stop();
+    }
+
+    @Test
+    public void resetCredentialsWithEmail() {
+        testRealmResetCredentialsPage.resetCredentials(testUser.getEmail());
+        resetCredentialsAndLoginWithNewPassword();
+    }
+    
+    @Test
+    public void resetCredentialsWithUsername() {
+        testRealmResetCredentialsPage.resetCredentials(testUser.getUsername());
+        resetCredentialsAndLoginWithNewPassword();
+    }
+    
+    private void resetCredentialsAndLoginWithNewPassword() {
+        assertEquals("You should receive an email shortly with further instructions.", 
+                testRealmResetCredentialsPage.getFeedbackText());
+        
+        String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, testUser.getEmail(), 
+                "Someone just requested to change your Test account's credentials.");
+        
+        log.info("navigating to " + url);
+        driver.navigate().to(url);
+        assertCurrentUrlStartsWith(testRealmResetCredentialsPage);
+        testRealmResetCredentialsPage.updatePassword("newPassword");
+        assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+        testRealmAccountManagementPage.signOut();
+        testRealmLoginPage.form().login("test", "newPassword");
+        assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/VerifyEmailTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/VerifyEmailTest.java
new file mode 100644
index 0000000..59e08cc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/VerifyEmailTest.java
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.AfterClass;
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.auth.page.login.VerifyEmail;
+import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl;
+import org.keycloak.testsuite.util.MailServer;
+import org.keycloak.testsuite.util.MailServerConfiguration;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+
+/**
+ *
+ * @author vramik
+ */
+public class VerifyEmailTest extends AbstractAccountManagementTest {
+
+    @Page
+    private VerifyEmail testRealmVerifyEmailPage;
+    
+    private static boolean init = false;
+   
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmVerifyEmailPage.setAuthRealm(testRealmPage);
+    }
+
+    @Before
+    public void beforeVerifyEmail() {
+        // enable verify email and configure smpt server in test realm
+        RealmRepresentation testRealmRep = testRealmResource().toRepresentation();
+        testRealmRep.setSmtpServer(suiteContext.getSmtpServer());
+        testRealmRep.setVerifyEmail(true);
+        testRealmResource().update(testRealmRep);
+
+        if (!init) {
+            init = true;
+            MailServer.start();
+            MailServer.createEmailAccount(testUser.getEmail(), "password");
+        }
+    }
+    
+    @AfterClass
+    public static void afterClass() {
+        MailServer.stop();
+    }
+
+    @Test
+    public void verifyEmail() {
+        testRealmAccountManagementPage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+        
+        assertEquals("You need to verify your email address to activate your account.", 
+                testRealmVerifyEmailPage.getFeedbackText());
+        
+        String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, testUser.getEmail(), 
+                "Someone has created a Test account with this email address.");
+        
+        log.info("navigating to " + url);
+        driver.navigate().to(url);
+        assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+        testRealmAccountManagementPage.signOut();
+        testRealmLoginPage.form().login(testUser);
+        assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
new file mode 100644
index 0000000..73ea7a6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
@@ -0,0 +1,139 @@
+package org.keycloak.testsuite.adapter;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractAuthTest;
+import org.keycloak.testsuite.arquillian.ContainersTestEnricher;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+import org.keycloak.testsuite.adapter.page.AppServerContextRoot;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer
+public abstract class AbstractAdapterTest extends AbstractAuthTest {
+
+    @Page
+    protected AppServerContextRoot appServerContextRootPage;
+
+    public static final String JBOSS_DEPLOYMENT_STRUCTURE_XML = "jboss-deployment-structure.xml";
+    public static final URL jbossDeploymentStructure = AbstractServletsAdapterTest.class
+            .getResource("/adapter-test/" + JBOSS_DEPLOYMENT_STRUCTURE_XML);
+    public static final String TOMCAT_CONTEXT_XML = "context.xml";
+    public static final URL tomcatContext = AbstractServletsAdapterTest.class
+            .getResource("/adapter-test/" + TOMCAT_CONTEXT_XML);
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        addAdapterTestRealms(testRealms);
+        for (RealmRepresentation tr : testRealms) {
+            log.info("Setting redirect-uris in test realm '" + tr.getRealm() + "' as " + (isRelative() ? "" : "non-") + "relative");
+
+            modifyClientRedirectUris(tr, "http://localhost:8080", "");
+            modifyClientUrls(tr, "http://localhost:8080", "");
+
+            if (isRelative()) {
+                modifyClientRedirectUris(tr, appServerContextRootPage.toString(), "");
+                modifyClientUrls(tr, appServerContextRootPage.toString(), "");
+                modifyClientWebOrigins(tr, "8080", System.getProperty("auth.server.http.port", null));
+            } else {
+                modifyClientRedirectUris(tr, "^(/.*/\\*)", appServerContextRootPage.toString() + "$1");
+                modifyClientUrls(tr, "^(/.*)", appServerContextRootPage.toString() + "$1");
+            }
+        }
+    }
+
+    public abstract void addAdapterTestRealms(List<RealmRepresentation> testRealms);
+
+    public boolean isRelative() {
+        return ContainersTestEnricher.isRelative(this.getClass());
+    }
+
+    protected void modifyClientRedirectUris(RealmRepresentation realm, String regex, String replacement) {
+        for (ClientRepresentation client : realm.getClients()) {
+            List<String> redirectUris = client.getRedirectUris();
+            if (redirectUris != null) {
+                List<String> newRedirectUris = new ArrayList<>();
+                for (String uri : redirectUris) {
+                    newRedirectUris.add(uri.replaceAll(regex, replacement));
+                }
+                client.setRedirectUris(newRedirectUris);
+            }
+        }
+    }
+
+    protected void modifyClientUrls(RealmRepresentation realm, String regex, String replacement) {
+        for (ClientRepresentation client : realm.getClients()) {
+            String baseUrl = client.getBaseUrl();
+            if (baseUrl != null) {
+                client.setBaseUrl(baseUrl.replaceAll(regex, replacement));
+            }
+            String adminUrl = client.getAdminUrl();
+            if (adminUrl != null) {
+                client.setAdminUrl(adminUrl.replaceAll(regex, replacement));
+            }
+        }
+    }
+
+    protected void modifyClientWebOrigins(RealmRepresentation realm, String regex, String replacement) {
+        for (ClientRepresentation client : realm.getClients()) {
+            List<String> webOrigins = client.getWebOrigins();
+            if (webOrigins != null) {
+                List<String> newWebOrigins = new ArrayList<>();
+                for (String uri : webOrigins) {
+                    newWebOrigins.add(uri.replaceAll(regex, replacement));
+                }
+                client.setWebOrigins(newWebOrigins);
+            }
+        }
+    }
+
+    /**
+     * Modifies baseUrl, adminUrl and redirectUris for client based on real
+     * deployment url of the app.
+     *
+     * @param realm
+     * @param clientId
+     * @param deploymentUrl
+     */
+    protected void fixClientUrisUsingDeploymentUrl(RealmRepresentation realm, String clientId, String deploymentUrl) {
+        for (ClientRepresentation client : realm.getClients()) {
+            if (clientId.equals(client.getClientId())) {
+                if (client.getBaseUrl() != null) {
+                    client.setBaseUrl(deploymentUrl);
+                }
+                if (client.getAdminUrl() != null) {
+                    client.setAdminUrl(deploymentUrl);
+                }
+                List<String> redirectUris = client.getRedirectUris();
+                if (redirectUris != null) {
+                    List<String> newRedirectUris = new ArrayList<>();
+                    for (String uri : redirectUris) {
+                        newRedirectUris.add(deploymentUrl + "/*");
+                    }
+                    client.setRedirectUris(newRedirectUris);
+                }
+            }
+        }
+    }
+
+    public static void addContextXml(Archive archive, String contextPath) {
+        try {
+            String contextXmlContent = IOUtils.toString(tomcatContext.openStream())
+                    .replace("%CONTEXT_PATH%", contextPath);
+            archive.add(new StringAsset(contextXmlContent), "/META-INF/context.xml");
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java
new file mode 100644
index 0000000..defb866
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java
@@ -0,0 +1,62 @@
+package org.keycloak.testsuite.adapter;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.IOUtils;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractExampleAdapterTest extends AbstractAdapterTest {
+
+    public static final String EXAMPLES_HOME;
+    public static final String EXAMPLES_VERSION_SUFFIX;
+    public static final String EXAMPLES_HOME_DIR;
+    public static final String EXAMPLES_WEB_XML;
+
+    static {
+        EXAMPLES_HOME = System.getProperty("examples.home", null);
+        Assert.assertNotNull("Property ${examples.home} must bet set.", EXAMPLES_HOME);
+        System.out.println(EXAMPLES_HOME);
+
+        EXAMPLES_VERSION_SUFFIX = System.getProperty("examples.version.suffix", null);
+        Assert.assertNotNull("Property ${examples.version.suffix} must bet set.", EXAMPLES_VERSION_SUFFIX);
+        System.out.println(EXAMPLES_VERSION_SUFFIX);
+
+        EXAMPLES_HOME_DIR = EXAMPLES_HOME + "/keycloak-examples-" + EXAMPLES_VERSION_SUFFIX;
+
+        EXAMPLES_WEB_XML = EXAMPLES_HOME + "/web.xml";
+    }
+
+    protected static WebArchive exampleDeployment(String name) throws IOException {
+        return ShrinkWrap.createFromZipFile(WebArchive.class,
+                new File(EXAMPLES_HOME + "/" + name + "-" + EXAMPLES_VERSION_SUFFIX + ".war"))
+                .addAsWebInfResource(jbossDeploymentStructure, JBOSS_DEPLOYMENT_STRUCTURE_XML);
+    }
+
+    protected static WebArchive exampleDeployment(String name, String contextPath) throws IOException {
+        URL webXML = Paths.get(EXAMPLES_WEB_XML).toUri().toURL();
+        String webXmlContent = IOUtils.toString(webXML.openStream())
+                .replace("%CONTEXT_PATH%", contextPath);
+        WebArchive webArchive = ShrinkWrap.createFromZipFile(WebArchive.class,
+                new File(EXAMPLES_HOME + "/" + name + "-" + EXAMPLES_VERSION_SUFFIX + ".war"))
+                .addAsWebInfResource(jbossDeploymentStructure, JBOSS_DEPLOYMENT_STRUCTURE_XML)
+                .add(new StringAsset(webXmlContent), "/WEB-INF/web.xml");
+        return webArchive;
+    }
+
+    protected static JavaArchive exampleJarDeployment(String name) {
+        return ShrinkWrap.createFromZipFile(JavaArchive.class,
+                new File(EXAMPLES_HOME + "/" + name + "-" + EXAMPLES_VERSION_SUFFIX + ".jar"));
+    }
+
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..7dc58c0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
@@ -0,0 +1,45 @@
+package org.keycloak.testsuite.adapter;
+
+import java.net.URL;
+import java.util.List;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.keycloak.representations.idm.RealmRepresentation;
+import static org.keycloak.testsuite.util.IOUtil.*;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+
+public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest {
+
+    protected static WebArchive servletDeployment(String name, Class... servletClasses) {
+        return servletDeployment(name, "keycloak.json", servletClasses);
+    }
+
+    protected static WebArchive servletDeployment(String name, String adapterConfig, Class... servletClasses) {
+        String webInfPath = "/adapter-test/" + name + "/WEB-INF/";
+
+        URL keycloakJSON = AbstractServletsAdapterTest.class.getResource(webInfPath + adapterConfig);
+        URL webXML = AbstractServletsAdapterTest.class.getResource(webInfPath + "web.xml");
+
+        WebArchive deployment = ShrinkWrap.create(WebArchive.class, name + ".war")
+                .addClasses(servletClasses)
+                .addAsWebInfResource(webXML, "web.xml")
+                .addAsWebInfResource(keycloakJSON, "keycloak.json")
+                .addAsWebInfResource(jbossDeploymentStructure, JBOSS_DEPLOYMENT_STRUCTURE_XML);
+
+        addContextXml(deployment, name);
+
+        return deployment;
+    }
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        testRealms.add(loadRealm("/adapter-test/demorealm.json"));
+    }
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(DEMO);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractBasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..8a592d9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractBasicAuthExampleAdapterTest.java
@@ -0,0 +1,68 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.core.Response;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import org.keycloak.testsuite.adapter.page.BasicAuthExample;
+import static org.keycloak.testsuite.auth.page.AuthRealm.EXAMPLE;
+
+public abstract class AbstractBasicAuthExampleAdapterTest extends AbstractExampleAdapterTest {
+
+    @Page
+    private BasicAuthExample basicAuthExample;
+
+    @Deployment(name = BasicAuthExample.DEPLOYMENT_NAME)
+    private static WebArchive basicAuthExample() throws IOException {
+        return exampleDeployment("examples-basicauth");
+    }
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        testRealms.add(loadRealm(new File(EXAMPLES_HOME_DIR + "/basic-auth/basicauthrealm.json")));
+    }
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(EXAMPLE);
+    }
+
+    @Test
+    public void testBasicAuthExample() {
+        String value = "hello";
+        Client client = ClientBuilder.newClient();
+
+        Response response = client.target(basicAuthExample
+                .setTemplateValues("admin", "password", value).buildUri()).request().get();
+        assertEquals(200, response.getStatus());
+        assertEquals(value, response.readEntity(String.class));
+        response.close();
+
+        response = client.target(basicAuthExample
+                .setTemplateValues("invalid-user", "password", value).buildUri()).request().get();
+        assertEquals(401, response.getStatus());
+        assertTrue(response.readEntity(String.class).contains("Unauthorized"));
+        response.close();
+
+        response = client.target(basicAuthExample
+                .setTemplateValues("admin", "invalid-password", value).buildUri()).request().get();
+        assertEquals(401, response.getStatus());
+        assertTrue(response.readEntity(String.class).contains("Unauthorized"));
+        response.close();
+
+        client.close();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java
new file mode 100644
index 0000000..72db4bb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java
@@ -0,0 +1,105 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import org.keycloak.testsuite.adapter.page.AngularCorsProductExample;
+import org.keycloak.testsuite.adapter.page.CorsDatabaseServiceExample;
+import org.keycloak.testsuite.arquillian.jira.Jira;
+import org.keycloak.testsuite.auth.page.account.Account;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ * Created by fkiss.
+ */
+public abstract class AbstractCorsExampleAdapterTest extends AbstractExampleAdapterTest {
+
+    public static final String CORS = "cors";
+
+    @Page
+    private AngularCorsProductExample angularCorsProductExample;
+
+    @Page
+    private Account testRealmAccount;
+
+    @Deployment(name = AngularCorsProductExample.DEPLOYMENT_NAME)
+    private static WebArchive angularCorsProductExample() throws IOException {
+        return exampleDeployment(AngularCorsProductExample.DEPLOYMENT_NAME, "angular-cors-product");
+    }
+
+    @Deployment(name = CorsDatabaseServiceExample.DEPLOYMENT_NAME)
+    private static WebArchive corsDatabaseServiceExample() throws IOException {
+        return exampleDeployment("database-service");
+    }
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        testRealms.add(
+                loadRealm(new File(EXAMPLES_HOME_DIR + "/cors/cors-realm.json")));
+    }
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(CORS);
+        testRealmLoginPage.setAuthRealm(CORS);
+        testRealmAccount.setAuthRealm(CORS);
+    }
+
+    @Before
+    public void beforeDemoExampleTest() {
+        angularCorsProductExample.navigateTo();
+        driver.manage().deleteAllCookies();
+    }
+
+    @Jira("KEYCLOAK-1546")
+    @Test
+    public void angularCorsProductTest() {
+        angularCorsProductExample.navigateTo();
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+        assertCurrentUrlStartsWith(angularCorsProductExample);
+        angularCorsProductExample.reloadData();
+        Assert.assertTrue(driver.getPageSource().contains("Product Listing"));
+        Assert.assertTrue(driver.getPageSource().contains("iphone"));
+        Assert.assertTrue(driver.getPageSource().contains("ipad"));
+        Assert.assertTrue(driver.getPageSource().contains("ipod"));
+
+        angularCorsProductExample.loadRoles();
+        Assert.assertTrue(driver.getPageSource().contains("Role Listing"));
+        Assert.assertTrue(driver.getPageSource().contains("user"));
+
+        angularCorsProductExample.addRole();
+        Assert.assertTrue(driver.getPageSource().contains("stuff"));
+
+        angularCorsProductExample.deleteRole();
+        Assert.assertFalse(driver.getPageSource().contains("stuff"));
+
+        angularCorsProductExample.loadAvailableSocialProviders();
+        Assert.assertTrue(driver.getPageSource().contains("Available social providers"));
+        Assert.assertTrue(driver.getPageSource().contains("twitter"));
+        Assert.assertTrue(driver.getPageSource().contains("google"));
+        Assert.assertTrue(driver.getPageSource().contains("linkedin"));
+        Assert.assertTrue(driver.getPageSource().contains("facebook"));
+        Assert.assertTrue(driver.getPageSource().contains("stackoverflow"));
+        Assert.assertTrue(driver.getPageSource().contains("github"));
+
+        angularCorsProductExample.loadPublicRealmInfo();
+        Assert.assertTrue(driver.getPageSource().contains("Realm name: cors"));
+
+        angularCorsProductExample.loadVersion();
+        Assert.assertTrue(driver.getPageSource().contains("Keycloak version: "));
+
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java
new file mode 100644
index 0000000..d31d390
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java
@@ -0,0 +1,157 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.*;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.auth.page.account.Account;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import org.keycloak.testsuite.adapter.page.CustomerPortalExample;
+import org.keycloak.testsuite.adapter.page.DatabaseServiceExample;
+import org.keycloak.testsuite.adapter.page.ProductPortalExample;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+import org.openqa.selenium.By;
+
+public abstract class AbstractDemoExampleAdapterTest extends AbstractExampleAdapterTest {
+
+    @Page
+    private CustomerPortalExample customerPortalExample;
+    @Page
+    private ProductPortalExample productPortalExample;
+    @Page
+    private DatabaseServiceExample databaseServiceExample;
+
+    @Page
+    private Account testRealmAccount;
+
+    @Deployment(name = CustomerPortalExample.DEPLOYMENT_NAME)
+    private static WebArchive customerPortalExample() throws IOException {
+        return exampleDeployment(CustomerPortalExample.DEPLOYMENT_NAME);
+    }
+
+    @Deployment(name = ProductPortalExample.DEPLOYMENT_NAME)
+    private static WebArchive productPortalExample() throws IOException {
+        return exampleDeployment(ProductPortalExample.DEPLOYMENT_NAME);
+    }
+
+    @Deployment(name = DatabaseServiceExample.DEPLOYMENT_NAME)
+    private static WebArchive databaseServiceExample() throws IOException {
+        return exampleDeployment("database-service");
+    }
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        testRealms.add(
+                loadRealm(new File(EXAMPLES_HOME_DIR + "/preconfigured-demo/testrealm.json")));
+    }
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(DEMO);
+        testRealmLoginPage.setAuthRealm(DEMO);
+        testRealmAccount.setAuthRealm(DEMO);
+    }
+
+    @Before
+    public void beforeDemoExampleTest() {
+        customerPortalExample.navigateTo();
+        driver.manage().deleteAllCookies();
+        productPortalExample.navigateTo();
+        driver.manage().deleteAllCookies();
+    }
+
+    @Test
+    public void customerPortalListingTest() {
+
+        customerPortalExample.navigateTo();
+        customerPortalExample.customerListing();
+
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+        assertCurrentUrlStartsWith(customerPortalExample);
+        customerPortalExample.waitForCustomerListingHeader();
+
+        Assert.assertTrue(driver.getPageSource().contains("Username: bburke@redhat.com"));
+        Assert.assertTrue(driver.getPageSource().contains("Bill Burke"));
+        Assert.assertTrue(driver.getPageSource().contains("Stian Thorgersen"));
+    }
+
+    @Test
+    public void customerPortalSessionTest() {
+
+        customerPortalExample.navigateTo();
+        customerPortalExample.customerSession();
+
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+        assertCurrentUrlStartsWith(customerPortalExample);
+
+        customerPortalExample.waitForCustomerSessionHeader();
+        Assert.assertTrue(driver.getPageSource().contains("You visited this page"));
+    }
+
+    @Test
+    public void productPortalListingTest() {
+
+        productPortalExample.navigateTo();
+        productPortalExample.productListing();
+
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+        assertCurrentUrlStartsWith(productPortalExample);
+        productPortalExample.waitForProductListingHeader();
+
+        Assert.assertTrue(driver.getPageSource().contains("iphone"));
+        Assert.assertTrue(driver.getPageSource().contains("ipad"));
+        Assert.assertTrue(driver.getPageSource().contains("ipod"));
+
+        productPortalExample.goToCustomers();
+    }
+
+    @Test
+    public void goToProductPortalWithOneLoginTest() {
+
+        productPortalExample.navigateTo();
+        productPortalExample.productListing();
+
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+        assertCurrentUrlStartsWith(productPortalExample);
+        productPortalExample.waitForProductListingHeader();
+        productPortalExample.goToCustomers();
+
+        assertCurrentUrlStartsWith(customerPortalExample);
+        customerPortalExample.customerListing();
+        customerPortalExample.goToProducts();
+        assertCurrentUrlStartsWith(productPortalExample);
+    }
+
+    @Test
+    public void logoutFromAllAppsTest() {
+
+        productPortalExample.navigateTo();
+        productPortalExample.productListing();
+
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+        assertCurrentUrlStartsWith(productPortalExample);
+        productPortalExample.waitForProductListingHeader();
+
+        productPortalExample.logOut();
+        assertCurrentUrlStartsWith(productPortalExample);
+        productPortalExample.productListing();
+
+        customerPortalExample.navigateTo();
+        customerPortalExample.customerListing();
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+        customerPortalExample.logOut();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java
new file mode 100644
index 0000000..647b15b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java
@@ -0,0 +1,131 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import java.io.File;
+import java.util.List;
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.auth.page.account.Account;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.adapter.AbstractExampleAdapterTest.EXAMPLES_HOME_DIR;
+import org.keycloak.testsuite.adapter.page.fuse.AdminInterface;
+import org.keycloak.testsuite.adapter.page.fuse.CustomerListing;
+import org.keycloak.testsuite.adapter.page.fuse.CustomerPortalFuseExample;
+import org.keycloak.testsuite.adapter.page.fuse.ProductPortalFuseExample;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractFuseExampleAdapterTest extends AbstractExampleAdapterTest {
+
+    @Page
+    protected CustomerPortalFuseExample customerPortal;
+    @Page
+    protected CustomerListing customerListing;
+    @Page
+    protected AdminInterface adminInterface;
+
+    @Page
+    protected ProductPortalFuseExample productPortal;
+
+    @Page
+    protected Account testRealmAccount;
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation fureRealm = loadRealm(new File(EXAMPLES_HOME_DIR + "/fuse/testrealm.json"));
+        testRealms.add(fureRealm);
+    }
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(DEMO);
+        testRealmLoginPage.setAuthRealm(DEMO);
+        testRealmAccount.setAuthRealm(DEMO);
+    }
+
+    // no Arquillian deployments - examples already installed by maven
+
+    @Test
+    public void testCustomerListingAndAccountManagement() {
+        customerPortal.navigateTo();
+        assertCurrentUrlStartsWith(customerPortal);
+
+        customerPortal.clickCustomerListingLink();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlStartsWith(customerListing);
+
+        String src = driver.getPageSource();
+        assertTrue(src.contains("Username: bburke@redhat.com")
+                && src.contains("Bill Burke")
+                && src.contains("Stian Thorgersen")
+        );
+
+        // account mgmt
+        customerListing.clickAccountManagement();
+
+        assertCurrentUrlStartsWith(testRealmAccount);
+        assertEquals(testRealmAccount.getUsername(), "bburke@redhat.com");
+
+        driver.navigate().back();
+        customerListing.clickLogOut();
+
+        // assert user not logged in
+        customerPortal.clickCustomerListingLink();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+    }
+
+    @Test
+    public void testAdminInterface() {
+        customerPortal.navigateTo();
+        assertCurrentUrlStartsWith(customerPortal);
+
+        customerPortal.clickAdminInterfaceLink();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        testRealmLoginPage.form().login("admin", "password");
+        assertCurrentUrlStartsWith(adminInterface);
+        assertTrue(driver.getPageSource().contains("Hello admin!"));
+
+        customerListing.navigateTo();
+        customerListing.clickLogOut();
+        pause(500);
+        assertCurrentUrlStartsWith(customerPortal);
+
+        customerPortal.clickAdminInterfaceLink();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlStartsWith(adminInterface);
+        assertTrue(driver.getPageSource().contains("Status code is 403"));
+    }
+
+    @Test
+    public void testProductPortal() {
+        productPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlStartsWith(productPortal);
+
+        assertTrue(productPortal.getProduct1UnsecuredText().contains("401: Unauthorized"));
+        assertTrue(productPortal.getProduct1SecuredText().contains("Product received: id=1"));
+        assertTrue(productPortal.getProduct2SecuredText().contains("Product received: id=2"));
+
+        productPortal.clickLogOutLink();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
new file mode 100644
index 0000000..61d8efa
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
@@ -0,0 +1,133 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import org.keycloak.testsuite.adapter.page.JSConsoleExample;
+import static org.keycloak.testsuite.auth.page.AuthRealm.EXAMPLE;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+
+public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampleAdapterTest {
+
+    @Page
+    private JSConsoleExample jsConsoleExample;
+
+    public static int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
+
+    @Deployment(name = JSConsoleExample.DEPLOYMENT_NAME)
+    private static WebArchive jsConsoleExample() throws IOException {
+        return exampleDeployment(JSConsoleExample.CLIENT_ID);
+    }
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation jsConsoleRealm = loadRealm(new File(EXAMPLES_HOME_DIR + "/js-console/example-realm.json"));
+
+        fixClientUrisUsingDeploymentUrl(jsConsoleRealm,
+                JSConsoleExample.CLIENT_ID, jsConsoleExample.buildUri().toASCIIString());
+
+        jsConsoleRealm.setAccessTokenLifespan(30 + TOKEN_LIFESPAN_LEEWAY); // seconds
+
+        testRealms.add(jsConsoleRealm);
+    }
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(EXAMPLE);
+    }
+
+    @Test
+    public void testJSConsoleAuth() {
+        jsConsoleExample.navigateTo();
+        assertCurrentUrlStartsWith(jsConsoleExample);
+
+        pause(1000);
+
+        jsConsoleExample.logIn();
+        testRealmLoginPage.form().login("user", "invalid-password");
+        assertCurrentUrlDoesntStartWith(jsConsoleExample);
+
+        testRealmLoginPage.form().login("invalid-user", "password");
+        assertCurrentUrlDoesntStartWith(jsConsoleExample);
+
+        testRealmLoginPage.form().login("user", "password");
+        assertCurrentUrlStartsWith(jsConsoleExample);
+        assertTrue(driver.getPageSource().contains("Init Success (Authenticated)"));
+        assertTrue(driver.getPageSource().contains("Auth Success"));
+
+        pause(1000);
+
+        jsConsoleExample.logOut();
+        assertCurrentUrlStartsWith(jsConsoleExample);
+        assertTrue(driver.getPageSource().contains("Init Success (Not Authenticated)"));
+    }
+
+    @Test
+    public void testRefreshToken() {
+        jsConsoleExample.navigateTo();
+        assertCurrentUrlStartsWith(jsConsoleExample);
+
+        jsConsoleExample.refreshToken();
+        assertTrue(driver.getPageSource().contains("Failed to refresh token"));
+
+        jsConsoleExample.logIn();
+        testRealmLoginPage.form().login("user", "password");
+        assertCurrentUrlStartsWith(jsConsoleExample);
+        assertTrue(driver.getPageSource().contains("Auth Success"));
+
+        jsConsoleExample.refreshToken();
+        assertTrue(driver.getPageSource().contains("Auth Refresh Success"));
+    }
+
+    @Test
+    public void testRefreshTokenIfUnder30s() {
+        jsConsoleExample.navigateTo();
+        assertCurrentUrlStartsWith(jsConsoleExample);
+
+        jsConsoleExample.refreshToken();
+        assertTrue(driver.getPageSource().contains("Failed to refresh token"));
+
+        jsConsoleExample.logIn();
+        testRealmLoginPage.form().login("user", "password");
+        assertCurrentUrlStartsWith(jsConsoleExample);
+        assertTrue(driver.getPageSource().contains("Auth Success"));
+
+        jsConsoleExample.refreshTokenIfUnder30s();
+        assertTrue(driver.getPageSource().contains("Token not refreshed, valid for"));
+
+        pause((TOKEN_LIFESPAN_LEEWAY + 2) * 1000);
+
+        jsConsoleExample.refreshTokenIfUnder30s();
+        assertTrue(driver.getPageSource().contains("Auth Refresh Success"));
+    }
+    
+    @Test 
+    public void testGetProfile() {
+        jsConsoleExample.navigateTo();
+        assertCurrentUrlStartsWith(jsConsoleExample);
+        
+        jsConsoleExample.getProfile();
+        assertTrue(driver.getPageSource().contains("Failed to load profile"));
+        
+        jsConsoleExample.logIn();
+        testRealmLoginPage.form().login("user", "password");
+        assertCurrentUrlStartsWith(jsConsoleExample);
+        assertTrue(driver.getPageSource().contains("Auth Success"));
+
+        jsConsoleExample.getProfile();
+        assertTrue(driver.getPageSource().contains("Failed to load profile"));
+        assertTrue(driver.getPageSource().contains("\"username\": \"user\""));
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
new file mode 100644
index 0000000..38e47b7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
@@ -0,0 +1,386 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.Version;
+import org.keycloak.constants.AdapterConstants;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.adapter.page.CustomerDb;
+import org.keycloak.testsuite.adapter.page.CustomerDbErrorPage;
+import org.keycloak.testsuite.adapter.page.CustomerPortal;
+import org.keycloak.testsuite.adapter.page.InputPortal;
+import org.keycloak.testsuite.adapter.page.ProductPortal;
+import org.keycloak.testsuite.adapter.page.SecurePortal;
+import org.keycloak.testsuite.arquillian.jira.Jira;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import org.keycloak.util.BasicAuthHelper;
+import org.keycloak.util.Time;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAdapterTest {
+
+    @Page
+    private CustomerPortal customerPortal;
+    @Page
+    private SecurePortal securePortal;
+    @Page
+    private CustomerDb customerDb;
+    @Page
+    private CustomerDbErrorPage customerDbErrorPage;
+    @Page
+    private ProductPortal productPortal;
+    @Page
+    private InputPortal inputPortal;
+
+    @Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
+    protected static WebArchive customerPortal() {
+        return servletDeployment(CustomerPortal.DEPLOYMENT_NAME, CustomerServlet.class, ErrorServlet.class);
+    }
+
+    @Deployment(name = SecurePortal.DEPLOYMENT_NAME)
+    protected static WebArchive securePortal() {
+        return servletDeployment(SecurePortal.DEPLOYMENT_NAME, CallAuthenticatedServlet.class);
+    }
+
+    @Deployment(name = CustomerDb.DEPLOYMENT_NAME)
+    protected static WebArchive customerDb() {
+        return servletDeployment(CustomerDb.DEPLOYMENT_NAME, CustomerDatabaseServlet.class);
+    }
+
+    @Deployment(name = CustomerDbErrorPage.DEPLOYMENT_NAME)
+    protected static WebArchive customerDbErrorPage() {
+        return servletDeployment(CustomerDbErrorPage.DEPLOYMENT_NAME, CustomerDatabaseServlet.class, ErrorServlet.class);
+    }
+
+    @Deployment(name = ProductPortal.DEPLOYMENT_NAME)
+    protected static WebArchive productPortal() {
+        return servletDeployment(ProductPortal.DEPLOYMENT_NAME, ProductServlet.class);
+    }
+
+    @Deployment(name = InputPortal.DEPLOYMENT_NAME)
+    protected static WebArchive inputPortal() {
+        return servletDeployment(InputPortal.DEPLOYMENT_NAME, "keycloak.json", InputServlet.class);
+    }
+
+    @Test
+    public void testSavedPostRequest() throws InterruptedException {
+        // test login to customer-portal which does a bearer request to customer-db
+        inputPortal.navigateTo();
+        assertCurrentUrlEquals(inputPortal);
+        inputPortal.execute("hello");
+
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertEquals(driver.getCurrentUrl(), inputPortal + "/secured/post");
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("parameter=hello"));
+
+        String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+                .queryParam(OAuth2Constants.REDIRECT_URI, customerPortal.toString())
+                .build("demo").toString();
+        driver.navigate().to(logoutUri);
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        productPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        customerPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        // test unsecured POST KEYCLOAK-901
+        Client client = ClientBuilder.newClient();
+        Form form = new Form();
+        form.param("parameter", "hello");
+        String text = client.target(inputPortal + "/unsecured").request().post(Entity.form(form), String.class);
+        assertTrue(text.contains("parameter=hello"));
+        client.close();
+    }
+
+    @Test
+    public void testLoginSSOAndLogout() {
+        // test login to customer-portal which does a bearer request to customer-db
+        customerPortal.navigateTo();
+        testRealmLoginPage.form().waitForUsernameInputPresent();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlEquals(customerPortal);
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+        // test SSO
+        productPortal.navigateTo();
+        assertCurrentUrlEquals(productPortal);
+        pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad"));
+
+        // View stats
+        List<Map<String, String>> stats = testRealmResource().getClientSessionStats();
+        Map<String, String> customerPortalStats = null;
+        Map<String, String> productPortalStats = null;
+        for (Map<String, String> s : stats) {
+            switch (s.get("clientId")) {
+                case "customer-portal":
+                    customerPortalStats = s;
+                    break;
+                case "product-portal":
+                    productPortalStats = s;
+                    break;
+            }
+        }
+        assertEquals(1, Integer.parseInt(customerPortalStats.get("active")));
+        assertEquals(1, Integer.parseInt(productPortalStats.get("active")));
+
+        // test logout
+        String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+                .queryParam(OAuth2Constants.REDIRECT_URI, customerPortal.toString()).build("demo").toString();
+        driver.navigate().to(logoutUri);
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        productPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        customerPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+//        testRealmLoginPage.form().cancel();
+//        assertTrue(driver.getPageSource().contains("Error Page"));
+    }
+
+    @Test
+    public void testServletRequestLogout() {
+        // test login to customer-portal which does a bearer request to customer-db
+        customerPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlEquals(customerPortal);
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+        // test SSO
+        productPortal.navigateTo();
+        assertCurrentUrlEquals(productPortal);
+        pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad"));
+
+        // back
+        customerPortal.navigateTo();
+        assertCurrentUrlEquals(customerPortal);
+        pageSource = driver.getPageSource();
+        Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+        // test logout
+
+        driver.navigate().to(customerPortal + "/logout");
+        assertTrue(driver.getPageSource().contains("servlet logout ok"));
+
+        customerPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        productPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+    }
+
+    @Test
+    public void testLoginSSOIdle() {
+        // test login to customer-portal which does a bearer request to customer-db
+        customerPortal.navigateTo();
+        testRealmLoginPage.form().waitForUsernameInputPresent();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlEquals(customerPortal);
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+        RealmRepresentation demoRealmRep = testRealmResource().toRepresentation();
+        int originalIdle = demoRealmRep.getSsoSessionIdleTimeout();
+        demoRealmRep.setSsoSessionIdleTimeout(1);
+        testRealmResource().update(demoRealmRep);
+
+//		Thread.sleep(2000);
+        productPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        demoRealmRep.setSsoSessionIdleTimeout(originalIdle);
+        testRealmResource().update(demoRealmRep);
+    }
+
+    @Test
+    @Jira(value = "KEYCLOAK-1478") // rejected
+    public void testLoginSSOIdleRemoveExpiredUserSessions() {
+        // test login to customer-portal which does a bearer request to customer-db
+        customerPortal.navigateTo();
+        log.info("Current url: " + driver.getCurrentUrl());
+        testRealmLoginPage.form().waitForUsernameInputPresent();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        log.info("Current url: " + driver.getCurrentUrl());
+        assertCurrentUrlEquals(customerPortal);
+        String pageSource = driver.getPageSource();
+        log.info(pageSource);
+        Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+        RealmRepresentation demoRealmRep = testRealmResource().toRepresentation();
+        int originalIdle = demoRealmRep.getSsoSessionIdleTimeout();
+        demoRealmRep.setSsoSessionIdleTimeout(1);
+        testRealmResource().update(demoRealmRep);
+
+        Time.setOffset(2);
+
+        productPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        // need to cleanup so other tests don't fail, so invalidate http sessions on remote clients.
+        demoRealmRep.setSsoSessionIdleTimeout(originalIdle);
+        // note: sessions invalidated after each test, see: AbstractKeycloakTest.afterAbstractKeycloakTest()
+
+        Time.setOffset(0);
+    }
+
+    @Test
+    public void testLoginSSOMax() throws InterruptedException {
+        // test login to customer-portal which does a bearer request to customer-db
+        customerPortal.navigateTo();
+        testRealmLoginPage.form().waitForUsernameInputPresent();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlEquals(customerPortal);
+        String pageSource = driver.getPageSource();
+        Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+        RealmRepresentation demoRealmRep = testRealmResource().toRepresentation();
+        int originalIdle = demoRealmRep.getSsoSessionMaxLifespan();
+        demoRealmRep.setSsoSessionMaxLifespan(1);
+        testRealmResource().update(demoRealmRep);
+
+        TimeUnit.SECONDS.sleep(2);
+        productPortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        demoRealmRep.setSsoSessionIdleTimeout(originalIdle);
+        testRealmResource().update(demoRealmRep);
+    }
+
+    @Jira("KEYCLOAK-518")
+    @Test
+    public void testNullBearerToken() {
+        Client client = ClientBuilder.newClient();
+        WebTarget target = client.target(customerDb.toString());
+        Response response = target.request().get();
+        assertEquals(401, response.getStatus());
+        response.close();
+        response = target.request().header(HttpHeaders.AUTHORIZATION, "Bearer null").get();
+        assertEquals(401, response.getStatus());
+        response.close();
+        client.close();
+    }
+
+    @Jira("KEYCLOAK-1368")
+    @Test
+    public void testNullBearerTokenCustomErrorPage() {
+        Client client = ClientBuilder.newClient();
+        WebTarget target = client.target(customerDbErrorPage.toString());
+        Response response = target.request().get();
+
+        // TODO: follow redirects automatically if possible
+        if (response.getStatus() == 302) {
+            String location = response.getHeaderString(HttpHeaders.LOCATION);
+            response.close();
+            response = client.target(location).request().get();
+        }
+        assertEquals(200, response.getStatus());
+        String errorPageResponse = response.readEntity(String.class);
+        assertTrue(errorPageResponse.contains("Error Page"));
+        response.close();
+
+        response = target.request().header(HttpHeaders.AUTHORIZATION, "Bearer null").get();
+        // TODO: follow redirects automatically if possible
+        if (response.getStatus() == 302) {
+            String location = response.getHeaderString(HttpHeaders.LOCATION);
+            response.close();
+            response = client.target(location).request().get();
+        }
+        assertEquals(200, response.getStatus());
+        errorPageResponse = response.readEntity(String.class);
+        assertTrue(errorPageResponse.contains("Error Page"));
+        response.close();
+
+        client.close();
+    }
+
+    @Jira("KEYCLOAK-518")
+    @Test
+    public void testBadUser() {
+        Client client = ClientBuilder.newClient();
+        URI uri = OIDCLoginProtocolService.tokenUrl(authServerPage.createUriBuilder()).build("demo");
+        WebTarget target = client.target(uri);
+        String header = BasicAuthHelper.createHeader("customer-portal", "password");
+        Form form = new Form();
+        form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
+                .param("username", "monkey@redhat.com")
+                .param("password", "password");
+        Response response = target.request()
+                .header(HttpHeaders.AUTHORIZATION, header)
+                .post(Entity.form(form));
+        assertEquals(401, response.getStatus());
+        response.close();
+        client.close();
+
+    }
+
+    @Test
+    public void testVersion() {
+        Client client = ClientBuilder.newClient();
+        WebTarget target = client.target(authServerPage.createUriBuilder()).path("version");
+        Version version = target.request().get(Version.class);
+        assertNotNull(version);
+        assertNotNull(version.getVersion());
+        assertNotNull(version.getBuildTime());
+        assertNotEquals(version.getVersion(), Version.UNKNOWN);
+        assertNotEquals(version.getBuildTime(), Version.UNKNOWN);
+
+        Version version2 = client.target(securePortal.toString()).path(AdapterConstants.K_VERSION).request().get(Version.class);
+        assertNotNull(version2);
+        assertNotNull(version2.getVersion());
+        assertNotNull(version2.getBuildTime());
+        assertEquals(version.getVersion(), version2.getVersion());
+        assertEquals(version.getBuildTime(), version2.getBuildTime());
+        client.close();
+    }
+
+    @Test
+    public void testAuthenticated() {
+        // test login to customer-portal which does a bearer request to customer-db
+        securePortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlEquals(securePortal);
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+        // test logout
+        String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+                .queryParam(OAuth2Constants.REDIRECT_URI, securePortal.toString()).build("demo").toString();
+        driver.navigate().to(logoutUri);
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        securePortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java
new file mode 100644
index 0000000..79c0bef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java
@@ -0,0 +1,184 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.After;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.adapter.page.SessionPortal;
+import org.keycloak.testsuite.arquillian.jira.Jira;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+import org.keycloak.testsuite.auth.page.account.Sessions;
+import org.keycloak.testsuite.auth.page.login.Login;
+import static org.keycloak.testsuite.admin.ApiUtil.findClientResourceByClientId;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import org.keycloak.testsuite.util.SecondBrowser;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractSessionServletAdapterTest extends AbstractServletsAdapterTest {
+
+    @Page
+    private SessionPortal sessionPortalPage;
+
+    @Page
+    private Sessions testRealmSessions;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmSessions.setAuthRealm(DEMO);
+    }
+
+    @Deployment(name = SessionPortal.DEPLOYMENT_NAME)
+    protected static WebArchive sessionPortal() {
+        return servletDeployment(SessionPortal.DEPLOYMENT_NAME, "keycloak.json", SessionServlet.class);
+    }
+
+    @After
+    public void afterSessionServletAdapterTest() {
+        sessionPortalPage.navigateTo();
+        driver.manage().deleteAllCookies();
+    }
+
+    @Drone
+    @SecondBrowser
+    protected WebDriver driver2;
+
+    @Jira("KEYCLOAK-732")
+    @Test
+    public void testSingleSessionInvalidated() {
+
+        loginAndCheckSession(driver, testRealmLoginPage);
+
+        // cannot pass to loginAndCheckSession becayse loginPage is not working together with driver2, therefore copypasta
+        driver2.navigate().to(sessionPortalPage.toString());
+        assertCurrentUrlStartsWithLoginUrlOf(driver2, testRealmPage);
+        driver2.findElement(By.id("username")).sendKeys("bburke@redhat.com");
+        driver2.findElement(By.id("password")).sendKeys("password");
+        driver2.findElement(By.id("password")).submit();
+        assertCurrentUrlEquals(driver2, sessionPortalPage);
+        String pageSource = driver2.getPageSource();
+        assertTrue(pageSource.contains("Counter=1"));
+        // Counter increased now
+        driver2.navigate().to(sessionPortalPage.toString());
+        pageSource = driver2.getPageSource();
+        assertTrue(pageSource.contains("Counter=2"));
+
+        // Logout in browser1
+        String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+                .queryParam(OAuth2Constants.REDIRECT_URI, sessionPortalPage.toString()).build("demo").toString();
+        driver.navigate().to(logoutUri);
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        // Assert that I am logged out in browser1
+        sessionPortalPage.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+        // Assert that I am still logged in browser2 and same session is still preserved
+        driver2.navigate().to(sessionPortalPage.toString());
+        assertCurrentUrlEquals(driver2, sessionPortalPage);
+        pageSource = driver2.getPageSource();
+        assertTrue(pageSource.contains("Counter=3"));
+
+        driver2.navigate().to(logoutUri);
+        assertCurrentUrlStartsWithLoginUrlOf(driver2, testRealmPage);
+
+    }
+
+    @Test
+    @Jira("KEYCLOAK-741, KEYCLOAK-1485")
+    public void testSessionInvalidatedAfterFailedRefresh() {
+        RealmRepresentation testRealmRep = testRealmResource().toRepresentation();
+        ClientResource sessionPortalRes = null;
+        for (ClientRepresentation clientRep : testRealmResource().clients().findAll()) {
+            if ("session-portal".equals(clientRep.getClientId())) {
+                sessionPortalRes = testRealmResource().clients().get(clientRep.getId());
+            }
+        }
+        assertNotNull(sessionPortalRes);
+        sessionPortalRes.toRepresentation().setAdminUrl("");
+        int origTokenLifespan = testRealmRep.getAccessCodeLifespan();
+        testRealmRep.setAccessCodeLifespan(1);
+        testRealmResource().update(testRealmRep);
+
+        // Login
+        loginAndCheckSession(driver, testRealmLoginPage);
+
+        // Logout
+        String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+                .queryParam(OAuth2Constants.REDIRECT_URI, sessionPortalPage.toString()).build("demo").toString();
+        driver.navigate().to(logoutUri);
+
+        // Assert that http session was invalidated
+        sessionPortalPage.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertEquals(driver.getCurrentUrl(), sessionPortalPage.toString());
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Counter=1"));
+
+        sessionPortalRes.toRepresentation().setAdminUrl(sessionPortalPage.toString());
+        testRealmRep.setAccessCodeLifespan(origTokenLifespan);
+        testRealmResource().update(testRealmRep);
+    }
+
+    @Test
+    @Jira("KEYCLOAK-942")
+    public void testAdminApplicationLogout() {
+        // login as bburke
+        loginAndCheckSession(driver, testRealmLoginPage);
+        // logout mposolda with admin client
+        findClientResourceByClientId(testRealmResource(), "session-portal")
+                .logoutUser("mposolda");
+        // bburke should be still logged with original httpSession in our browser window
+        sessionPortalPage.navigateTo();
+        assertEquals(driver.getCurrentUrl(), sessionPortalPage.toString());
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Counter=3"));
+        String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+                .queryParam(OAuth2Constants.REDIRECT_URI, sessionPortalPage.toString()).build("demo").toString();
+        driver.navigate().to(logoutUri);
+    }
+
+    @Test
+    @Jira("KEYCLOAK-1216, KEYCLOAK-1485")
+    public void testAccountManagementSessionsLogout() {
+        // login as bburke
+        loginAndCheckSession(driver, testRealmLoginPage);
+        testRealmSessions.navigateTo();
+        testRealmSessions.logoutAll();
+        // Assert I need to login again (logout was propagated to the app)
+        loginAndCheckSession(driver, testRealmLoginPage);
+    }
+
+    private void loginAndCheckSession(WebDriver driver, Login login) {
+        sessionPortalPage.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        login.form().login("bburke@redhat.com", "password");
+        assertEquals(driver.getCurrentUrl(), sessionPortalPage.toString());
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Counter=1"));
+
+        // Counter increased now
+        sessionPortalPage.navigateTo();
+        pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Counter=2"));
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java
new file mode 100644
index 0000000..573363a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java
@@ -0,0 +1,111 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.AbstractAuthTest;
+import org.keycloak.testsuite.console.page.AdminConsole;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm.ConfigureMenu;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm.ManageMenu;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.login.Login;
+import org.keycloak.testsuite.console.page.fragment.ModalDialog;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public abstract class AbstractConsoleTest extends AbstractAuthTest {
+
+    @Page
+    protected AdminConsole adminConsolePage;
+    @Page
+    protected AdminConsoleRealm adminConsoleRealmPage;
+
+    @Page
+    protected AdminConsole testRealmAdminConsolePage;
+    
+    @FindBy(xpath = "//div[@class='modal-dialog']")
+    protected ModalDialog modalDialog;
+
+    protected boolean adminLoggedIn = false;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(TEST);
+        testRealmAdminConsolePage.setAdminRealm(TEST);
+    }
+
+    @Before
+    public void beforeConsoleTest() {
+        createTestUserWithAdminClient();
+        if (!testContext.isAdminLoggedIn()) {
+            loginToMasterRealmAdminConsoleAs(adminUser);
+            testContext.setAdminLoggedIn(true);
+        } else {
+//            adminConsoleRealmPage.navigateTo();
+        }
+    }
+
+    public void loginToMasterRealmAdminConsoleAs(UserRepresentation user) {
+        loginToAdminConsoleAs(adminConsolePage, loginPage, user);
+    }
+
+    public void logoutFromMasterRealmConsole() {
+        logoutFromAdminConsole(adminConsolePage);
+    }
+
+    public void loginToTestRealmConsoleAs(UserRepresentation user) {
+        loginToAdminConsoleAs(testRealmAdminConsolePage, testRealmLoginPage, user);
+    }
+
+    public void logoutFromTestRealmConsole() {
+        logoutFromAdminConsole(testRealmAdminConsolePage);
+    }
+
+    public void loginToAdminConsoleAs(AdminConsole adminConsole, Login login, UserRepresentation user) {
+        adminConsole.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(adminConsole);
+        login.form().login(user);
+        assertCurrentUrlStartsWith(adminConsole);
+    }
+
+    public void logoutFromAdminConsole(AdminConsole adminConsole) {
+        adminConsole.navigateTo();
+        assertCurrentUrlStartsWith(adminConsole);
+        adminConsole.logOut();
+        assertCurrentUrlStartsWithLoginUrlOf(adminConsole);
+    }
+
+    public ConfigureMenu configure() {
+        return adminConsoleRealmPage.configure();
+    }
+
+    public ManageMenu manage() {
+        return adminConsoleRealmPage.manage();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java
new file mode 100644
index 0000000..75cf70f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java
@@ -0,0 +1,164 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.authentication;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.authentication.PasswordPolicy;
+
+import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.*;
+import org.keycloak.testsuite.console.page.users.UserCredentials;
+
+/**
+ * @author Petr Mensik
+ * @author mhajas
+ */
+//@Ignore // FIXME still unstable
+public class PasswordPolicyTest extends AbstractConsoleTest {
+
+    @Page
+    private PasswordPolicy passwordPolicyPage;
+
+    @Page
+    private UserCredentials testUserCredentialsPage;
+
+    @Before
+    public void beforePasswordPolicyTest() {
+        testUserCredentialsPage.setId(testUser.getId());
+        passwordPolicyPage.navigateTo();
+    }
+
+    @Test
+    public void testAddAndRemovePolicy() {
+        passwordPolicyPage.addPolicy(HASH_ITERATIONS, 5);
+        passwordPolicyPage.removePolicy(HASH_ITERATIONS);
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void testInvalidPolicyValues() {
+        passwordPolicyPage.addPolicy(HASH_ITERATIONS, "asd");
+        assertFlashMessageDanger();
+        passwordPolicyPage.removePolicy(HASH_ITERATIONS);
+
+        passwordPolicyPage.addPolicy(REGEX_PATTERN, "^[A-Z]{8,5}");
+        assertFlashMessageDanger();
+    }
+
+    @Test
+    public void testLengthPolicy() {
+        passwordPolicyPage.addPolicy(LENGTH, 8);
+
+        testUserCredentialsPage.navigateTo();
+        testUserCredentialsPage.resetPassword("1234567");
+        assertFlashMessageDanger();
+
+        testUserCredentialsPage.resetPassword("12345678");
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void testDigitsPolicy() {
+        passwordPolicyPage.addPolicy(DIGITS, 2);
+
+        testUserCredentialsPage.navigateTo();
+        testUserCredentialsPage.resetPassword("invalidPassword1");
+        assertFlashMessageDanger();
+
+        testUserCredentialsPage.resetPassword("validPassword12");
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void testLowerCasePolicy() {
+        passwordPolicyPage.addPolicy(LOWER_CASE, 2);
+
+        testUserCredentialsPage.navigateTo();
+        testUserCredentialsPage.resetPassword("iNVALIDPASSWORD");
+        assertFlashMessageDanger();
+
+        testUserCredentialsPage.resetPassword("vaLIDPASSWORD");
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void testUpperCasePolicy() {
+        passwordPolicyPage.addPolicy(UPPER_CASE, 2);
+
+        testUserCredentialsPage.navigateTo();
+        testUserCredentialsPage.resetPassword("Invalidpassword");
+        assertFlashMessageDanger();
+
+        testUserCredentialsPage.resetPassword("VAlidpassword");
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void testSpecialCharsPolicy() {
+        passwordPolicyPage.addPolicy(SPECIAL_CHARS, 2);
+
+        testUserCredentialsPage.navigateTo();
+        testUserCredentialsPage.resetPassword("invalidPassword*");
+        assertFlashMessageDanger();
+
+        testUserCredentialsPage.resetPassword("validPassword*#");
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void testNotUsernamePolicy() {
+        passwordPolicyPage.addPolicy(NOT_USERNAME);
+
+        testUserCredentialsPage.navigateTo();
+        testUserCredentialsPage.resetPassword(testUser.getUsername());
+        assertFlashMessageDanger();
+
+        testUserCredentialsPage.resetPassword("validpassword");
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void testRegexPatternsPolicy() {
+        passwordPolicyPage.addPolicy(REGEX_PATTERN, "^[A-Z]+#[a-z]{8}$");
+
+        testUserCredentialsPage.navigateTo();
+        testUserCredentialsPage.resetPassword("invalidPassword");
+        assertFlashMessageDanger();
+
+        testUserCredentialsPage.resetPassword("VALID#password");
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void testPasswordHistoryPolicy() {
+        passwordPolicyPage.addPolicy(PASSWORD_HISTORY, 2);
+
+        testUserCredentialsPage.navigateTo();
+        testUserCredentialsPage.resetPassword("firstPassword");
+        assertFlashMessageSuccess();
+
+        testUserCredentialsPage.resetPassword("secondPassword");
+        assertFlashMessageSuccess();
+
+        testUserCredentialsPage.resetPassword("firstPassword");
+        assertFlashMessageDanger();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/RequiredActionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/RequiredActionsTest.java
new file mode 100644
index 0000000..9c818d1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/RequiredActionsTest.java
@@ -0,0 +1,137 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.authentication;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.auth.page.login.Registration;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.authentication.RequiredActions;
+import org.keycloak.testsuite.console.page.realm.LoginSettings;
+import org.openqa.selenium.By;
+
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+
+/**
+ * @author Petr Mensik
+ * @author mhajas
+ */
+public class RequiredActionsTest extends AbstractConsoleTest {
+
+    @Page
+    private RequiredActions requiredActionsPage;
+
+    @Page
+    private LoginSettings loginSettingsPage;
+
+    @Page
+    private Registration testRealmRegistrationPage;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmRegistrationPage.setAuthRealm("test");
+    }
+    
+    @Before
+    public void beforeRequiredActionsTest() {
+        requiredActionsPage.navigateTo();
+    }
+
+    @Test
+    public void requiredActionsTest() {
+        requiredActionsPage.clickTermsAndConditionEnabled();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickTermsAndConditionDefaultAction();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickVerifyEmailEnabled();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickVerifyEmailDefaultAction();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickUpdatePasswordEnabled();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickUpdatePasswordDefaultAction();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickConfigureTotpEnabled();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickConfigureTotpDefaultAction();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickUpdateProfileEnabled();
+        assertFlashMessageSuccess();
+
+        requiredActionsPage.clickUpdateProfileDefaultAction();
+        assertFlashMessageSuccess();
+    }
+
+    @Test
+    public void termsAndConditionsDefaultActionTest() {
+        requiredActionsPage.clickTermsAndConditionEnabled();
+        requiredActionsPage.clickTermsAndConditionDefaultAction();
+
+        allowTestRealmUserRegistration();
+
+        navigateToTestRealmRegistration();
+
+        registerTestUser();
+
+        driver.findElement(By.xpath("//div[@id='kc-header-wrapper' and text()[contains(.,'Terms and Conditions')]]"));
+    }
+
+    @Test
+    public void configureTotpDefaultActionTest() {
+        requiredActionsPage.clickConfigureTotpDefaultAction();
+
+        allowTestRealmUserRegistration();
+
+        navigateToTestRealmRegistration();
+
+        registerTestUser();
+
+        driver.findElement(By.xpath("//div[@id='kc-header-wrapper' and text()[contains(.,'Mobile Authenticator Setup')]]"));
+    }
+
+    private void allowTestRealmUserRegistration() {
+        loginSettingsPage.navigateTo();
+        loginSettingsPage.form().setRegistrationAllowed(true);
+        loginSettingsPage.form().save();
+    }
+
+    private void navigateToTestRealmRegistration() {
+        testRealmAdminConsolePage.navigateTo();
+        testRealmLoginPage.form().register();
+    }
+
+    private void registerTestUser() {
+        UserRepresentation user = createUserRepresentation("testUser", "testUser@email.test", "test", "user", true);
+        setPasswordFor(user, PASSWORD);
+
+        testRealmRegistrationPage.register(user);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
new file mode 100644
index 0000000..6c40d64
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
@@ -0,0 +1,74 @@
+package org.keycloak.testsuite.console.clients;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.auth.page.login.OIDCLogin.OIDC;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.clients.Client;
+import org.keycloak.testsuite.console.page.clients.Clients;
+import org.keycloak.testsuite.console.page.clients.CreateClient;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractClientTest extends AbstractConsoleTest {
+
+    @Page
+    protected Clients clientsPage;
+    @Page
+    protected Client clientPage; // note: cannot call navigateTo() unless client id is set
+    @Page
+    protected CreateClient createClientPage;
+
+    @Before
+    public void beforeClientTest() {
+//        configure().clients();
+        clientsPage.navigateTo();
+    }
+
+    public void createClient(ClientRepresentation client) {
+        assertCurrentUrlEquals(clientsPage);
+        clientsPage.table().createClient();
+        createClientPage.form().setValues(client);
+        createClientPage.form().save();
+    }
+
+    public void deleteClientViaTable(String clientId) {
+        assertCurrentUrlEquals(clientsPage);
+        clientsPage.deleteClient(clientId);
+    }
+
+    public void deleteClientViaPage(String clientId) {
+        assertCurrentUrlEquals(clientsPage);
+        clientsPage.table().search(clientId);
+        clientsPage.table().clickClient(clientId);
+        clientPage.delete();
+    }
+
+    public static ClientRepresentation createClientRepresentation(String clientId, String... redirectUris) {
+        ClientRepresentation client = new ClientRepresentation();
+        client.setClientId(clientId);
+        client.setEnabled(true);
+        client.setConsentRequired(false);
+        client.setDirectGrantsOnly(false);
+        
+        client.setProtocol(OIDC);
+        
+        client.setBearerOnly(false);
+        client.setPublicClient(false);
+        client.setServiceAccountsEnabled(false);
+        
+        List<String> redirectUrisList = new ArrayList();
+        redirectUrisList.addAll(Arrays.asList(redirectUris));
+        client.setRedirectUris(redirectUrisList);
+        
+        return client;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java
new file mode 100644
index 0000000..e005d60
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java
@@ -0,0 +1,273 @@
+package org.keycloak.testsuite.console.clients;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+import org.keycloak.testsuite.console.page.users.UserRoleMappingsForm;
+
+import static org.junit.Assert.*;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.clients.ClientRole;
+import org.keycloak.testsuite.console.page.clients.ClientRoles;
+import org.keycloak.testsuite.console.page.clients.CreateClientRole;
+import org.keycloak.testsuite.console.page.users.User;
+
+/**
+ * Created by fkiss.
+ */
+public class ClientRolesTest extends AbstractClientTest {
+
+    @Page
+    private ClientRoles clientRolesPage;
+    @Page
+    private CreateClientRole createClientRolePage;
+    @Page
+    private ClientRole clientRolePage;
+
+    @Page
+    private User userPage; // note: cannot call navigateTo() unless user id is set
+
+    @Page
+    private UserRoleMappingsForm userRolesPage;
+
+    public void addClientRole(RoleRepresentation roleRep) {
+//        assertCurrentUrl(clientRoles);
+        clientRolesPage.roles().addRole();
+//        assertCurrentUrl(createClientRole); // can't do this, need client id to build uri
+        createClientRolePage.form().setBasicAttributes(roleRep);
+        createClientRolePage.form().save();
+        assertFlashMessageSuccess();
+        createClientRolePage.form().setCompositeRoles(roleRep);
+        // TODO add verification of notification message when KEYCLOAK-1497 gets resolved
+    }
+
+    @Test
+    public void testAddClientRole() {
+        ClientRepresentation newClient = createClientRepresentation("test-client1", "http://example.com/*");
+        RoleRepresentation newRole = new RoleRepresentation("client-role", "");
+
+        createClient(newClient);
+        assertFlashMessageSuccess();
+
+        clientPage.tabs().roles();
+        addClientRole(newRole);
+        assertFlashMessageSuccess();
+
+        clientRolePage.backToClientRolesViaBreadcrumb();
+        assertFalse(clientRolesPage.roles().getRolesFromTableRows().isEmpty());
+
+        configure().clients();
+        clientsPage.table().search(newClient.getClientId());
+        clientsPage.table().deleteClient(newClient.getClientId());
+        modalDialog.confirmDeletion();
+        assertFlashMessageSuccess();
+        assertNull(clientsPage.table().findClient(newClient.getClientId()));
+    }
+
+//    @Test
+//    @Jira("KEYCLOAK-1497")
+//    public void testAddClientRoleToUser() {
+//        ClientRepresentation newClient = createClientRepresentation("test-client2", "http://example.com/*");
+//        RoleRepresentation newRole = new RoleRepresentation("client-role2", "");
+//        String testUsername = "test-user2";
+//        UserRepresentation newUser = new UserRepresentation();
+//        newUser.setUsername(testUsername);
+//        newUser.credential(PASSWORD, "pass");
+//
+//        createClient(newClient);
+//        assertFlashMessageSuccess();
+//
+//        client.tabs().roles();
+//        addClientRole(newRole);
+//        assertFlashMessageSuccess();
+//
+//        clientRole.backToClientRolesViaBreadcrumb();
+//        assertFalse(clientRoles.table().searchRoles(newRole.getName()).isEmpty());
+//
+//        users.navigateTo();
+//        createUser(newUser);
+//        flashMessage.waitUntilPresent();
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+//        users.navigateTo();
+//        users.findUser(testUsername);
+//        users.clickUser(testUsername);
+//
+//        user.tabs().roleMappings();
+//        roleMappings.selectClientRole(newClient.getClientId());
+//        roleMappings.addAvailableClientRole(newRole.getName());
+//        //flashMessage.waitUntilPresent();
+//        //assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        //KEYCLOAK-1497
+//        assertTrue(roleMappings.isAssignedClientRole(newRole.getName()));
+//
+//        users.navigateTo();
+//        users.deleteUser(testUsername);
+//
+//        clients.navigateTo();
+//        clients.deleteClient(newClient.getClientId());
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        assertNull(clients.findClient(newClient.getClientId()));
+//    }
+//
+//    @Test
+//    @Jira("KEYCLOAK-1496, KEYCLOAK-1497")
+//    @Ignore // TODO use REST to create test data (user/roles)
+//    public void testAddCompositeRealmClientRoleToUser() {
+//        ClientRepresentation newClient = createClientRepresentation("test-client3", "http://example.com/*");
+//        RoleRepresentation clientCompositeRole = new RoleRepresentation("client-composite-role", "");
+//        String testUsername = "test-user3";
+//        UserRepresentation newUser = new UserRepresentation();
+//        newUser.setUsername(testUsername);
+//        newUser.credential(PASSWORD, "pass");
+//
+//        RoleRepresentation subRole1 = new RoleRepresentation("sub-role1", "");
+//        RoleRepresentation subRole2 = new RoleRepresentation("sub-role2", "");
+//        List<RoleRepresentation> testRoles = new ArrayList<>();
+//        clientCompositeRole.setComposite(true);
+//        testRoles.add(subRole1);
+//        testRoles.add(subRole2);
+//
+//        //create sub-roles
+//        configure().roles();
+//        for (RoleRepresentation role : testRoles) {
+//            realmRoles.addRole(role);
+//            flashMessage.waitUntilPresent();
+//            assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//            configure().roles();
+//            assertEquals(role.getName(), realmRoles.findRole(role.getName()).getName());
+//        }
+//
+//        //create client
+//        clients.navigateTo();
+//        createClient(newClient);
+//        flashMessage.waitUntilPresent();
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+//        //add client role
+//        configure().roles();
+//        realmRoles.addRole(clientCompositeRole);
+//        flashMessage.waitUntilPresent();
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+//        //add realm composite roles
+//        realmRoles.setCompositeRole(clientCompositeRole);
+//        roleMappings.addAvailableRole(subRole1.getName(), subRole2.getName());
+//        //flashMessage.waitUntilPresent();
+//        //assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        //KEYCLOAK-1497
+//
+//        //create user
+//        users.navigateTo();
+//        createUser(newUser);
+//        flashMessage.waitUntilPresent();
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+//        //add client role to user and verify
+//        users.navigateTo();
+//        users.findUser(testUsername);
+//        users.clickUser(testUsername);
+//
+//        user.tabs().roleMappings();
+//        roleMappings.selectClientRole(newClient.getClientId());
+//        roleMappings.addAvailableClientRole(clientCompositeRole.getName());
+//        //flashMessage.waitUntilPresent();
+//        //assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        //KEYCLOAK-1497
+//        assertTrue(roleMappings.isAssignedClientRole(clientCompositeRole.getName()));
+//        assertTrue(roleMappings.isEffectiveRealmRolesComplete(subRole1, subRole2)); //KEYCLOAK-1496
+//        assertTrue(roleMappings.isEffectiveClientRolesComplete(clientCompositeRole));
+//
+//        //delete everything
+//        users.navigateTo();
+//        users.deleteUser(testUsername);
+//
+//        configure().roles();
+//        realmRoles.deleteRole(subRole1);
+//        configure().roles();
+//        realmRoles.deleteRole(subRole2);
+//
+//        clients.navigateTo();
+//        clients.deleteClient(newClient.getClientId());
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        assertNull(clients.findClient(newClient.getClientId()));
+//    }
+//
+//    @Test
+//    @Jira("KEYCLOAK-1504, KEYCLOAK-1497")
+//    public void testAddCompositeClientRoleToUser() {
+//        ClientRepresentation newClient = createClientRepresentation("test-client4", "http://example.com/*");
+//        RoleRepresentation clientCompositeRole = new RoleRepresentation("client-composite-role2", "");
+//        String testUsername = "test-user4";
+//        UserRepresentation newUser = new UserRepresentation();
+//        newUser.setUsername(testUsername);
+//        newUser.credential(PASSWORD, "pass");
+//
+//        RoleRepresentation subRole1 = new RoleRepresentation("client-sub-role1", "");
+//        RoleRepresentation subRole2 = new RoleRepresentation("client-sub-role2", "");
+//        List<RoleRepresentation> testRoles = new ArrayList<>();
+//        clientCompositeRole.setComposite(true);
+//        testRoles.add(clientCompositeRole);
+//        testRoles.add(subRole1);
+//        testRoles.add(subRole2);
+//
+//        //create client
+//        createClient(newClient);
+//        flashMessage.waitUntilPresent();
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+//        //create sub-roles
+//        configure().roles();
+//        for (RoleRepresentation role : testRoles) {
+//            clients.navigateTo();
+//            clients.clickClient(newClient.getClientId());
+//            configure().roles();
+//            realmRoles.addRole(role);
+//            flashMessage.waitUntilPresent();
+//            assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        }
+//
+//        //add client composite roles
+//        clients.navigateTo();
+//        clients.clickClient(newClient);
+//        configure().roles();
+//        realmRoles.clickRole(clientCompositeRole);
+//        realmRoles.setCompositeRole(clientCompositeRole);
+//        roleMappings.selectClientRole(newClient.getClientId());
+//        roleMappings.addAvailableClientRole(subRole1.getName(), subRole2.getName());
+//        //flashMessage.waitUntilPresent();
+//        //assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        //KEYCLOAK-1504, KEYCLOAK-1497
+//
+//        //create user
+//        users.navigateTo();
+//        createUser(newUser);
+//        flashMessage.waitUntilPresent();
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+//        //add client role to user and verify
+//        users.navigateTo();
+//        users.findUser(testUsername);
+//        users.clickUser(testUsername);
+//
+//        user.tabs().roleMappings();
+//        roleMappings.selectClientRole(newClient.getClientId());
+//        roleMappings.addAvailableClientRole(clientCompositeRole.getName());
+//        assertTrue(roleMappings.isAssignedClientRole(clientCompositeRole.getName()));
+//        assertTrue(roleMappings.isEffectiveClientRolesComplete(clientCompositeRole, subRole1, subRole2));
+//
+//        //delete everything
+//        users.navigateTo();
+//        users.deleteUser(testUsername);
+//
+//        configure().roles();
+//        realmRoles.deleteRole(subRole1);
+//        configure().roles();
+//        realmRoles.deleteRole(subRole2);
+//
+//        clients.navigateTo();
+//        clients.deleteClient(newClient.getClientId());
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        assertNull(clients.findClient(newClient.getClientId()));
+//    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
new file mode 100644
index 0000000..5229527
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
@@ -0,0 +1,163 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.clients;
+
+import javax.ws.rs.core.Response;
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.getCreatedId;
+import org.keycloak.testsuite.console.page.clients.ClientSettings;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsBooleanAttributes;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsListAttributes;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsStringAttributes;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.keycloak.testsuite.util.Timer;
+
+/**
+ *
+ * @author Filip Kiss
+ * @author tkyjovsk
+ */
+public class ClientSettingsTest extends AbstractClientTest {
+
+    @Page
+    private ClientSettings clientSettingsPage;
+
+    private ClientRepresentation newClient;
+
+    public void crudOIDCConfidential() {
+        newClient = createClientRepresentation("oidc-confidential", "http://example.test/app/*");
+        createClient(newClient);
+        assertFlashMessageSuccess();
+
+        clientPage.backToClientsViaBreadcrumb();
+        assertCurrentUrlEquals(clientsPage);
+        assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
+
+        // read & verify
+        clientsPage.table().clickClient(newClient);
+        ClientRepresentation found = clientSettingsPage.form().getValues();
+        assertClientSettingsEqual(newClient, found);
+
+        // update & verify
+        // TODO change attributes, add redirect uris and weborigins
+        // delete
+        // TODO
+        clientPage.backToClientsViaBreadcrumb();
+    }
+
+    public void createOIDCPublic() {
+        newClient = createClientRepresentation("oidc-public", "http://example.test/app/*");
+        newClient.setPublicClient(true);
+        createClient(newClient);
+        assertFlashMessageSuccess();
+
+        clientPage.backToClientsViaBreadcrumb();
+        assertCurrentUrlEquals(clientsPage);
+        assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
+    }
+
+    public void createOIDCBearerOnly() {
+        newClient = createClientRepresentation("oidc-bearer-only", "http://example.test/app/*");
+        newClient.setBearerOnly(true);
+        createClient(newClient);
+        assertFlashMessageSuccess();
+
+        clientPage.backToClientsViaBreadcrumb();
+        assertCurrentUrlEquals(clientsPage);
+        assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
+    }
+
+    @Test
+    public void successfulCRUD() {
+        crudOIDCConfidential();
+        createOIDCPublic();
+        createOIDCBearerOnly();
+    }
+
+    @Test
+    public void invalidSettings() {
+        clientsPage.table().createClient();
+        createClientPage.form().save();
+        assertFlashMessageDanger();
+
+        createClientPage.form().setClientId("test-client");
+        createClientPage.form().save();
+        assertFlashMessageDanger();
+    }
+
+    public void assertClientSettingsEqual(ClientRepresentation c1, ClientRepresentation c2) {
+        assertEqualsStringAttributes(c1.getClientId(), c2.getClientId());
+        assertEqualsStringAttributes(c1.getName(), c2.getName());
+        assertEqualsBooleanAttributes(c1.isEnabled(), c2.isEnabled());
+        assertEqualsBooleanAttributes(c1.isConsentRequired(), c2.isConsentRequired());
+        assertEqualsBooleanAttributes(c1.isDirectGrantsOnly(), c2.isDirectGrantsOnly());
+        assertEqualsStringAttributes(c1.getProtocol(), c2.getProtocol());
+
+        assertEqualsBooleanAttributes(c1.isBearerOnly(), c2.isBearerOnly());
+        assertEqualsBooleanAttributes(c1.isPublicClient(), c2.isPublicClient());
+        assertEqualsBooleanAttributes(c1.isSurrogateAuthRequired(), c2.isSurrogateAuthRequired());
+
+        assertEqualsBooleanAttributes(c1.isFrontchannelLogout(), c2.isFrontchannelLogout());
+
+        assertEqualsBooleanAttributes(c1.isServiceAccountsEnabled(), c2.isServiceAccountsEnabled());
+        assertEqualsListAttributes(c1.getRedirectUris(), c2.getRedirectUris());
+        assertEqualsStringAttributes(c1.getBaseUrl(), c2.getBaseUrl());
+        assertEqualsStringAttributes(c1.getAdminUrl(), c2.getAdminUrl());
+        assertEqualsListAttributes(c1.getWebOrigins(), c2.getWebOrigins());
+    }
+
+//    @Test
+    public void createInconsistentClient() {
+        ClientRepresentation c = createClientRepresentation("inconsistent_client");
+        c.setPublicClient(true);
+        c.setBearerOnly(true);
+
+        Response r = clientsPage.clientsResource().create(c);
+        r.close();
+        clientSettingsPage.setId(getCreatedId(r));
+
+        c = clientSettingsPage.clientResource().toRepresentation();
+        assertTrue(c.isBearerOnly());
+        assertTrue(c.isPublicClient());
+    }
+
+    public void createClients(String clientIdPrefix, int count) {
+        for (int i = 0; i < count; i++) {
+            String clientId = String.format("%s%02d", clientIdPrefix, i);
+            ClientRepresentation cr = createClientRepresentation(clientId, "http://example.test/*");
+            Timer.time();
+            Response r = testRealmResource().clients().create(cr);
+            r.close();
+            Timer.time("create client");
+        }
+    }
+
+//    @Test
+    public void clientsPagination() {
+        createClients("test_client_", 100);
+        clientsPage.navigateTo();
+        pause(120000);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java
new file mode 100644
index 0000000..5b22ca4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java
@@ -0,0 +1,84 @@
+package org.keycloak.testsuite.console.events;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.clients.AbstractClientTest;
+import org.keycloak.testsuite.console.page.clients.Clients;
+import org.keycloak.testsuite.console.page.events.AdminEvents;
+import org.keycloak.testsuite.console.page.events.Config;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+
+/**
+ * @author mhajas
+ */
+public class AdminEventsTest extends AbstractConsoleTest {
+
+    @Page
+    private AdminEvents adminEventsPage;
+
+    @Page
+    private Config configPage;
+
+    @Page
+    private Clients clientsPage;
+
+    private ClientRepresentation newClient;
+
+    @Before
+    public void beforeAdminEventsTest() {
+        configPage.navigateTo();
+        configPage.form().setSaveAdminEvents(true);
+        configPage.form().setIncludeRepresentation(true);
+        configPage.form().save();
+    }
+
+    @Test
+    public void clientsAdminEventsTest() {
+        newClient = AbstractClientTest.createClientRepresentation("test_client", "http://example.test/test_client/*");
+        Response response = clientsPage.clientsResource().create(newClient);
+        String id = ApiUtil.getCreatedId(response);
+        response.close();
+        newClient.setClientId("test_client2");
+        clientsPage.clientsResource().get(id).update(newClient);
+        clientsPage.clientsResource().get(id).remove();
+
+        adminEventsPage.navigateTo();
+        adminEventsPage.table().filter();
+        adminEventsPage.table().filterForm().addOperationType("CREATE");
+        adminEventsPage.table().update();
+
+        List<WebElement> resultList = adminEventsPage.table().rows();
+        assertEquals(1, resultList.size());
+        resultList.get(0).findElement(By.xpath("//td[text()='CREATE']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
+
+        adminEventsPage.table().reset();
+        adminEventsPage.table().filterForm().addOperationType("UPDATE");
+        adminEventsPage.table().update();
+
+        resultList = adminEventsPage.table().rows();
+        assertEquals(1, resultList.size());
+        resultList.get(0).findElement(By.xpath("//td[text()='UPDATE']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
+
+        adminEventsPage.table().reset();
+        adminEventsPage.table().filterForm().addOperationType("DELETE");
+        adminEventsPage.table().update();
+
+        resultList = adminEventsPage.table().rows();
+        assertEquals(1, resultList.size());
+        resultList.get(0).findElement(By.xpath("//td[text()='DELETE']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
new file mode 100644
index 0000000..078c56d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
@@ -0,0 +1,85 @@
+package org.keycloak.testsuite.console.events;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.testsuite.admin.Users;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.events.Config;
+import org.keycloak.testsuite.console.page.events.LoginEvents;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+
+/**
+ * @author mhajas
+ */
+public class LoginEventsTest extends AbstractConsoleTest {
+    @Page
+    private LoginEvents loginEventsPage;
+
+    @Page
+    private Config configPage;
+
+    @Before
+    public void beforeLoginEventsTest() {
+        configPage.navigateTo();
+        configPage.form().setSaveEvents(true);
+        configPage.form().addSaveType("LOGIN");
+        configPage.form().addSaveType("LOGIN_ERROR");
+        configPage.form().addSaveType("LOGOUT");
+        configPage.form().save();
+    }
+
+    @Test
+    public void userAccessEventsTest() {
+        testRealmAdminConsolePage.navigateTo();
+        Users.setPasswordFor(testUser, "Wrong_password");
+        testRealmLoginPage.form().login(testUser);
+        Users.setPasswordFor(testUser, PASSWORD);
+        testRealmLoginPage.form().login(testUser);
+        testRealmAdminConsolePage.logOut();
+
+        loginEventsPage.navigateTo();
+        loginEventsPage.table().filter();
+
+        loginEventsPage.table().filterForm().addEventType("LOGIN");
+        loginEventsPage.table().update();
+
+        List<WebElement> resultList = loginEventsPage.table().rows();
+
+        assertEquals(7, resultList.size());
+        resultList.get(0).findElement(By.xpath("//td[text()='LOGIN']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='Client']/../td[text()='security-admin-console']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
+
+        loginEventsPage.table().reset();
+        loginEventsPage.table().filterForm().addEventType("LOGOUT");
+        loginEventsPage.table().update();
+
+        resultList = loginEventsPage.table().rows();
+
+        assertEquals(2, resultList.size());
+        resultList.get(0).findElement(By.xpath("//td[text()='LOGOUT']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
+
+        loginEventsPage.table().reset();
+        loginEventsPage.table().filterForm().addEventType("LOGIN_ERROR");
+        loginEventsPage.table().update();
+
+        resultList = loginEventsPage.table().rows();
+
+        assertEquals(6, resultList.size());
+        resultList.get(0).findElement(By.xpath("//td[text()='LOGIN_ERROR']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='Client']/../td[text()='security-admin-console']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='Error']/../td[text()='invalid_user_credentials']"));
+        resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/federation/LdapUserFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/federation/LdapUserFederationTest.java
new file mode 100644
index 0000000..e70da46
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/federation/LdapUserFederationTest.java
@@ -0,0 +1,71 @@
+package org.keycloak.testsuite.console.federation;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.*;
+import org.keycloak.models.LDAPConstants;
+
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.federation.LdapUserProviderForm;
+import org.keycloak.testsuite.console.page.federation.UserFederation;
+import org.keycloak.testsuite.console.page.users.Users;
+import org.keycloak.testsuite.util.LDAPTestConfiguration;
+
+import java.util.Map;
+
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+
+/**
+ * Created by fkiss.
+ */
+public class LdapUserFederationTest extends AbstractConsoleTest {
+
+    @Page
+    private LdapUserProviderForm ldapUserProviderForm;
+
+    @Page
+    private UserFederation userFederationPage;
+
+    @Page
+    private Users usersPage;
+
+    @Before
+    public void beforeTestLdapUserFederation() {
+        //configure().userFederation();
+    }
+
+    @Ignore
+    @Test
+    public void addAndConfigureProvider() {
+        adminConsolePage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+
+        String name = "ldapname";
+
+        String LDAP_CONNECTION_PROPERTIES_LOCATION = "ldap/ldap-connection.properties";
+        LDAPTestConfiguration ldapTestConfiguration = LDAPTestConfiguration.readConfiguration(LDAP_CONNECTION_PROPERTIES_LOCATION);
+
+        UserRepresentation newUser = new UserRepresentation();
+        String testUsername = "defaultrole tester";
+        newUser.setUsername(testUsername);
+        setPasswordFor(newUser, PASSWORD);
+
+        Map<String,String> ldapConfig = ldapTestConfiguration.getLDAPConfig();
+
+        //addLdapProviderTest
+        configure().userFederation();
+        userFederationPage.addProvider("ldap");
+        ldapUserProviderForm.configureLdap(ldapConfig.get(LDAPConstants.LDAP_PROVIDER), ldapConfig.get(LDAPConstants.EDIT_MODE), ldapConfig.get(LDAPConstants.VENDOR), ldapConfig.get(LDAPConstants.CONNECTION_URL), ldapConfig.get(LDAPConstants.USERS_DN), ldapConfig.get(LDAPConstants.BIND_DN), ldapConfig.get(LDAPConstants.BIND_CREDENTIAL));
+    }
+
+    @Ignore
+    @Test
+    public void caseSensitiveSearch() {
+        // This should fail for now due to case-sensitivity
+        adminConsolePage.navigateTo();
+        testRealmLoginPage.form().login("johnKeycloak", "Password1");
+        assertTrue(flashMessage.getText(), flashMessage.isDanger());
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/AbstractRealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/AbstractRealmTest.java
new file mode 100644
index 0000000..84de989
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/AbstractRealmTest.java
@@ -0,0 +1,27 @@
+package org.keycloak.testsuite.console.realm;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.realm.RealmSettings;
+import org.keycloak.testsuite.console.page.realm.RealmSettings.RealmTabs;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractRealmTest extends AbstractConsoleTest {
+
+    @Page
+    protected RealmSettings realmSettingsPage;
+
+    public RealmTabs tabs() {
+        return realmSettingsPage.tabs();
+    }
+    
+    @Before
+    public void beforeRealmTest() {
+//        configure().realmSettings();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java
new file mode 100644
index 0000000..eaae00c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java
@@ -0,0 +1,78 @@
+package org.keycloak.testsuite.console.realm;
+
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertFalse;
+import org.junit.Before;
+import org.junit.Test;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.console.page.realm.LoginSettings;
+import org.keycloak.testsuite.auth.page.login.Registration;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class LoginSettingsTest extends AbstractRealmTest {
+
+    @Page
+    private LoginSettings loginSettingsPage;
+
+    @Page
+    private Registration testRealmRegistrationPage;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmRegistrationPage.setAuthRealm(TEST);
+    }
+    
+    @Before
+    public void beforeLoginSettingsTest() {
+//        tabs().login();
+        loginSettingsPage.navigateTo();
+        assertCurrentUrlEquals(loginSettingsPage);
+    }
+
+    @Test
+    public void userRegistration() {
+
+        log.info("enabling registration");
+        loginSettingsPage.form().setRegistrationAllowed(true);
+        loginSettingsPage.form().save();
+        log.debug("enabled");
+        
+        testRealmAdminConsolePage.navigateTo();
+        testRealmLoginPage.form().register();
+        assertCurrentUrlStartsWith(testRealmRegistrationPage);
+        testRealmRegistrationPage.waitForUsernameInputPresent();
+        log.info("verified registration is enabled");
+
+        // test email as username
+        log.info("enabling email as username");
+        loginSettingsPage.navigateTo();
+        loginSettingsPage.form().setEmailAsUsername(true);
+        loginSettingsPage.form().save();
+        log.debug("enabled");
+
+        testRealmAdminConsolePage.navigateTo();
+        testRealmLoginPage.form().register();
+        assertCurrentUrlStartsWith(testRealmRegistrationPage);
+        testRealmRegistrationPage.waitForUsernameInputNotPresent();
+        log.info("verified email as username");
+
+        // test user reg. disabled
+        log.info("disabling registration");
+        loginSettingsPage.navigateTo();
+        loginSettingsPage.form().setRegistrationAllowed(false);
+        loginSettingsPage.form().save();
+        assertFalse(loginSettingsPage.form().isRegistrationAllowed());
+        log.debug("disabled");
+        
+        testRealmAdminConsolePage.navigateTo();
+        testRealmLoginPage.form().waitForRegisterLinkNotPresent();
+        log.info("verified regisration is disabled");
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java
new file mode 100644
index 0000000..84a9930
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java
@@ -0,0 +1,255 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.realm;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.testsuite.auth.page.account.Account;
+import org.keycloak.testsuite.console.page.realm.SecurityDefenses;
+import org.keycloak.testsuite.console.page.users.UserAttributes;
+import org.keycloak.testsuite.console.page.users.Users;
+import org.openqa.selenium.By;
+
+import java.util.Date;
+
+import static org.jboss.arquillian.graphene.Graphene.waitGui;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ * @author Filip Kiss
+ * @author mhajas
+ */
+public class SecurityDefensesTest extends AbstractRealmTest {
+
+    @Page
+    private SecurityDefenses.BruteForceDetection bruteForceDetectionPage;
+
+    @Page
+    private Account testRealmAccountPage;
+
+    @Page
+    private Users usersPage;
+
+    @Page
+    private UserAttributes userAttributesPage;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmAccountPage.setAuthRealm(TEST);
+    }
+
+    @Before
+    public void beforeSecurityDefensesTest() {
+        bruteForceDetectionPage.navigateTo();
+    }
+
+    @Test
+    public void maxLoginFailuresTest() {
+        int secondsToWait = 3;
+
+        bruteForceDetectionPage.form().setProtectionEnabled(true);
+        bruteForceDetectionPage.form().setMaxLoginFailures("1");
+        bruteForceDetectionPage.form().setWaitIncrementSelect(SecurityDefenses.TimeSelectValues.SECONDS);
+        bruteForceDetectionPage.form().setWaitIncrementInput(String.valueOf(secondsToWait));
+        bruteForceDetectionPage.form().save();
+        assertFlashMessageSuccess();
+
+        testRealmAccountPage.navigateTo();
+
+        setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+        testRealmLoginPage.form().login(testUser);
+        waitForFeedbackText("Invalid username or password.");
+        Date endTime = new Date(new Date().getTime() + secondsToWait * 1000);
+
+        testRealmLoginPage.form().login(testUser);
+        waitGui().until().element(By.className("instruction"))
+                .text().contains("Account is temporarily disabled, contact admin or try again later.");
+        endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+        testRealmAccountPage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+        endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+
+        while (new Date().compareTo(endTime) < 0) {
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        setPasswordFor(testUser, PASSWORD);
+        testRealmLoginPage.form().login(testUser);
+        assertCurrentUrlStartsWith(testRealmAccountPage);
+    }
+
+    @Test
+    public void quickLoginCheck() {
+        int secondsToWait = 3;
+
+        bruteForceDetectionPage.form().setProtectionEnabled(true);
+        bruteForceDetectionPage.form().setMaxLoginFailures("100");
+        bruteForceDetectionPage.form().setQuickLoginCheckInput("1500");
+        bruteForceDetectionPage.form().setMinQuickLoginWaitSelect(SecurityDefenses.TimeSelectValues.SECONDS);
+        bruteForceDetectionPage.form().setMinQuickLoginWaitInput(String.valueOf(secondsToWait));
+        bruteForceDetectionPage.form().save();
+        assertFlashMessageSuccess();
+
+        testRealmAccountPage.navigateTo();
+
+        setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+        testRealmLoginPage.form().login(testUser);
+        testRealmLoginPage.form().login(testUser);
+        Date endTime = new Date(new Date().getTime() + secondsToWait * 1000);
+        testRealmLoginPage.form().login(testUser);
+        waitGui().until().element(By.className("instruction"))
+                .text().contains("Account is temporarily disabled, contact admin or try again later.");
+        endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+
+        testRealmAccountPage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+        endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+
+        while (new Date().compareTo(endTime) < 0) {
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        setPasswordFor(testUser, PASSWORD);
+        testRealmLoginPage.form().login(testUser);
+        assertCurrentUrlStartsWith(testRealmAccountPage);
+    }
+
+    @Test
+    public void maxWaitLoginFailures() {
+        int secondsToWait = 5;
+
+        bruteForceDetectionPage.form().setProtectionEnabled(true);
+        bruteForceDetectionPage.form().setMaxLoginFailures("1");
+        bruteForceDetectionPage.form().setMaxWaitSelect(SecurityDefenses.TimeSelectValues.SECONDS);
+        bruteForceDetectionPage.form().setMaxWaitInput(String.valueOf(secondsToWait));
+        bruteForceDetectionPage.form().save();
+
+        testRealmAccountPage.navigateTo();
+
+        setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+        testRealmLoginPage.form().login(testUser);
+        Date endTime = new Date(new Date().getTime() + secondsToWait * 1000);
+        waitForFeedbackText("Invalid username or password.");
+
+        testRealmLoginPage.form().login(testUser);
+        endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+        waitGui().until().element(By.className("instruction"))
+                .text().contains("Account is temporarily disabled, contact admin or try again later.");
+        testRealmAccountPage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+        endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+        waitForFeedbackText("Account is temporarily disabled, contact admin or try again later.");
+
+        while (new Date().compareTo(endTime) < 0) {
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        setPasswordFor(testUser, PASSWORD);
+        testRealmLoginPage.form().login(testUser);
+        assertCurrentUrlStartsWith(testRealmAccountPage);
+    }
+
+    @Test
+    public void failureResetTime() {
+        int secondsToWait = 3;
+
+        bruteForceDetectionPage.form().setProtectionEnabled(true);
+        bruteForceDetectionPage.form().setMaxLoginFailures("2");
+        bruteForceDetectionPage.form().setFailureResetTimeSelect(SecurityDefenses.TimeSelectValues.SECONDS);
+        bruteForceDetectionPage.form().setFailureResetTimeInput(String.valueOf(secondsToWait));
+        bruteForceDetectionPage.form().save();
+        assertFlashMessageSuccess();
+
+        testRealmAccountPage.navigateTo();
+
+        setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+        testRealmLoginPage.form().login(testUser);
+        waitForFeedbackText("Invalid username or password.");
+        Date endTime = new Date(new Date().getTime() + secondsToWait * 1000);
+
+        while (new Date().compareTo(endTime) < 0) {
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        testRealmLoginPage.form().login(testUser);
+        waitForFeedbackText("Invalid username or password.");
+
+        setPasswordFor(testUser, PASSWORD);
+        testRealmLoginPage.form().login(testUser);
+        assertCurrentUrlStartsWith(testRealmAccountPage);
+    }
+
+    @Test
+    public void userUnlockTest() {
+        bruteForceDetectionPage.form().setProtectionEnabled(true);
+        bruteForceDetectionPage.form().setMaxLoginFailures("1");
+        bruteForceDetectionPage.form().setWaitIncrementSelect(SecurityDefenses.TimeSelectValues.MINUTES);
+        bruteForceDetectionPage.form().setWaitIncrementInput("10");
+        bruteForceDetectionPage.form().save();
+        assertFlashMessageSuccess();
+
+        testRealmAccountPage.navigateTo();
+
+        setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+        testRealmLoginPage.form().login(testUser);
+
+        usersPage.navigateTo();
+
+        usersPage.table().searchUsers(testUser.getUsername());
+        usersPage.table().editUser(testUser.getUsername());
+        userAttributesPage.form().unlockUser();
+
+        testRealmAccountPage.navigateTo();
+
+        setPasswordFor(testUser, PASSWORD);
+
+        testRealmLoginPage.form().login(testUser);
+        assertCurrentUrlStartsWith(testRealmAccountPage);
+    }
+
+    private void waitForFeedbackText(String text) {
+        waitGui().until().element(By.className("kc-feedback-text"))
+                .text().contains(text);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java
new file mode 100644
index 0000000..701e798
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java
@@ -0,0 +1,26 @@
+package org.keycloak.testsuite.console.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.roles.Roles;
+import org.keycloak.testsuite.console.page.users.User;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractRolesTest extends AbstractConsoleTest {
+    
+    @Page
+    protected Roles rolesPage;
+    
+    @Page
+    protected User userPage;
+    
+    @Before
+    public void beforeRolesTest() {
+//        configure().roles();
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java
new file mode 100644
index 0000000..2f3bd8e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java
@@ -0,0 +1,61 @@
+package org.keycloak.testsuite.console.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
+import org.keycloak.testsuite.console.page.roles.DefaultRoles;
+import org.keycloak.testsuite.console.page.users.UserRoleMappings;
+import org.keycloak.testsuite.console.page.users.Users;
+
+/**
+ * Created by fkiss.
+ */
+public class DefaultRolesTest extends AbstractRolesTest {
+
+    @Page
+    private DefaultRoles defaultRolesPage;
+
+    @Page
+    private UserRoleMappings userRolesPage;
+
+    private RoleRepresentation defaultRoleRep;
+
+    @Page
+    private Users users;
+
+    @Before
+    public void beforeDefaultRolesTest() {
+        // create a role via admin client
+        defaultRoleRep = new RoleRepresentation("default-role", "");
+        rolesPage.rolesResource().create(defaultRoleRep);
+
+        defaultRolesPage.navigateTo();
+        // navigate to default roles page
+//        rolesPage.tabs().defaultRoles();
+    }
+
+    @Test
+    public void defaultRoleAssignedToNewUser() {
+
+        String defaultRoleName = defaultRoleRep.getName();
+
+        defaultRolesPage.form().addAvailableRole(defaultRoleName);
+        assertFlashMessageSuccess();
+
+        UserRepresentation newUser = new UserRepresentation();
+        newUser.setUsername("new_user");
+
+        createUserWithAdminClient(testRealmResource(), newUser);
+        users.navigateTo();
+        users.table().search(newUser.getUsername());
+        users.table().clickUser(newUser.getUsername());
+
+        userPage.tabs().roleMappings();
+        assertTrue(userRolesPage.form().isAssignedRole(defaultRoleName));
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/RealmRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/RealmRolesTest.java
new file mode 100644
index 0000000..f92ccac
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/RealmRolesTest.java
@@ -0,0 +1,229 @@
+package org.keycloak.testsuite.console.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+import org.keycloak.testsuite.console.page.roles.RealmRoles;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.roles.CreateRole;
+import org.keycloak.testsuite.console.page.roles.Role;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.keycloak.testsuite.util.Timer;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class RealmRolesTest extends AbstractRolesTest {
+    
+    @Page
+    private RealmRoles realmRolesPage;
+    @Page
+    private CreateRole createRolePage;
+    @Page
+    private Role rolePage;
+    
+    private RoleRepresentation testRole;
+    
+    @Before
+    public void beforeTestAddNewRole() {
+        testRole = new RoleRepresentation("test_role", "role description");
+        realmRolesPage.navigateTo();
+    }
+    
+    public void addRole(RoleRepresentation roleRep) {
+        assertCurrentUrlEquals(realmRolesPage);
+        realmRolesPage.table().addRole();
+        assertCurrentUrlEquals(createRolePage);
+        createRolePage.form().setBasicAttributes(roleRep);
+        createRolePage.form().save();
+        assertFlashMessageSuccess();
+        createRolePage.form().setCompositeRoles(roleRep);
+        // TODO add verification of notification message when KEYCLOAK-1497 gets resolved
+    }
+    
+    public void updateRole(RoleRepresentation roleRep) {
+        assertCurrentUrlEquals(realmRolesPage);
+        realmRolesPage.table().editRole(roleRep.getName());
+//        assertCurrentUrl(role); // can't do this, role id needed as uri param
+        rolePage.form().setBasicAttributes(roleRep);
+        rolePage.form().save();
+        assertFlashMessageSuccess();
+        rolePage.form().setCompositeRoles(roleRep);
+    }
+    
+    public void assertBasicRoleAttributesEqual(RoleRepresentation r1, RoleRepresentation r2) {
+        assertEquals(r1.getName(), r2.getName());
+        assertEquals(r1.getDescription(), r2.getDescription());
+        assertEquals(r1.isComposite(), r2.isComposite());
+    }
+    
+    @Test
+    public void crudRole() {
+        addRole(testRole);
+        
+        configure().roles();
+        RoleRepresentation foundRole = realmRolesPage.table().findRole(testRole.getName()); // search & get role from table
+        assertBasicRoleAttributesEqual(testRole, foundRole);
+        realmRolesPage.table().editRole(testRole.getName());
+        foundRole = rolePage.form().getBasicAttributes();
+        assertBasicRoleAttributesEqual(testRole, foundRole);
+        
+        testRole.setDescription("updated role description");
+        rolePage.form().setDescription(testRole.getDescription());
+        rolePage.form().save();
+        assertFlashMessageSuccess();
+        
+        configure().roles();
+        foundRole = realmRolesPage.table().findRole(testRole.getName()); // search & get role from table
+        assertBasicRoleAttributesEqual(testRole, foundRole);
+
+        // delete from table
+        realmRolesPage.table().deleteRole(testRole.getName());
+        modalDialog.cancel();
+        assertTrue(realmRolesPage.table().containsRole(testRole.getName()));
+        realmRolesPage.table().deleteRole(testRole.getName());
+        modalDialog.confirmDeletion();
+        pause(250);
+        assertFalse(realmRolesPage.table().containsRole(testRole.getName()));
+
+        // add again
+        addRole(testRole);
+        // delete from page
+        rolePage.form().delete();
+        modalDialog.confirmDeletion();
+        assertCurrentUrlEquals(realmRolesPage);
+    }
+    
+    @Test
+    @Ignore
+    public void testAddRoleWithLongName() {
+        String name = "hjewr89y1894yh98(*&*&$jhjkashd)*(&y8934h*&@#hjkahsdj";
+        addRole(new RoleRepresentation(name, ""));
+        assertNotNull(realmRolesPage.table().findRole(name));
+    }
+    
+    @Test
+    public void testAddExistingRole() {
+        addRole(testRole);
+        assertFlashMessageSuccess();
+        
+        configure().roles();
+        realmRolesPage.table().addRole();
+        createRolePage.form().setBasicAttributes(testRole);
+        createRolePage.form().save();
+        assertFlashMessageDanger();
+    }
+    
+    public void createTestRoles(String namePrefix, int count) {
+        Timer.time();
+        for (int i = 0; i < count; i++) {
+            String roleName = String.format("%s%02d", namePrefix, i);
+            RoleRepresentation rr = new RoleRepresentation(roleName, "");
+            testRealmResource().roles().create(rr);
+        }
+        Timer.time("create " + count + " roles");
+    }
+
+//    @Test
+    public void rolesPagination() {
+        createTestRoles("test_role_", 100);
+        realmRolesPage.navigateTo();
+        pause(100000);
+    }
+
+//    @Test
+//    public void addAndRemoveUserAndAssignRole() {
+//        roleMappings.form().addAvailableRole("create-realm");
+//        assertFlashMessageSuccess();
+//        
+//        roleMappings.form().removeAssignedRole("create-realm");
+//        assertFlashMessageSuccess();
+//        
+//        users.navigateTo();
+//        users.table().deleteUser(testUsername);
+//    }
+//    @Test // this should be moved to users tests
+//    public void testRoleIsAvailableForUsers() {
+//        RoleRepresentation role = new RoleRepresentation("User role", "");
+//        roles.addRole(role);
+//        flashMessage.waitUntilPresent();
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        users.navigateTo();
+//        users.viewAllUsers();
+//        users.clickUser("admin");
+//        user.tabs().roleMappings();
+//        Select rolesSelect = new Select(driver.findElement(id("available")));
+//        assertEquals("User role should be present in admin role mapping",
+//                role.getName(), rolesSelect.getOptions().get(0).getText());
+//        roles.navigateTo();
+//        roles.deleteRole(role);
+//    }
+//
+//    @Ignore//KEYCLOAK-1497
+//    @Test
+//    public void testAddCompositeRole() {
+//        UserRepresentation testUserRep = new UserRepresentation();
+//        testUserRep.setUsername("usercomposite");
+//
+//        RoleRepresentation compositeRole = new RoleRepresentation("compositeRole", "");
+//        RoleRepresentation subRole1 = new RoleRepresentation("subRole1", "");
+//        RoleRepresentation subRole2 = new RoleRepresentation("subRole2", "");
+//        List<RoleRepresentation> testRoles = new ArrayList<>();
+//        compositeRole.setComposite(true);
+//        testRoles.add(compositeRole);
+//        testRoles.add(subRole1);
+//        testRoles.add(subRole2);
+//
+//        //create roles and user
+//        for (RoleRepresentation role : testRoles) {
+//            roles.addRole(role);
+//            flashMessage.waitUntilPresent();
+//            assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//            roles.navigateTo();
+//            assertEquals(role.getName(), roles.findRole(role.getName()).getName());
+//        }
+//        users.navigateTo();
+//        createUser(testUserRep);
+//        flashMessage.waitUntilPresent();
+//        assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+//        //adding subroles to composite role
+//        roles.navigateTo();
+//        roles.findRole(compositeRole.getName());
+//        roles.clickRole(compositeRole);
+//        roles.setCompositeRole(compositeRole);
+//        roleMappings.addAvailableRole(subRole1.getName(), subRole2.getName());
+//        //flashMessage.waitUntilPresent();
+//        //assertTrue(flashMessage.getText(), flashMessage.isSuccess()); KEYCLOAK-1497
+//
+//        //check if subroles work as expected
+//        users.navigateTo();
+//        users.findUser(testUserRep.getUsername());
+//        users.clickUser(testUserRep.getUsername());
+//        user.tabs().roleMappings();
+//        roleMappings.addAvailableRole(compositeRole.getName());
+//        assertTrue(roleMappings.isEffectiveRealmRolesComplete(compositeRole, subRole1, subRole2));
+//
+//        //delete everything
+//        roles.navigateTo();
+//        roles.deleteRole(compositeRole);
+//        roles.navigateTo();
+//        roles.deleteRole(subRole1);
+//        roles.navigateTo();
+//        roles.deleteRole(subRole2);
+//        try {
+//            Thread.sleep(2000);
+//        } catch (InterruptedException e) {
+//            e.printStackTrace();
+//        }
+//        users.navigateTo();
+//        users.deleteUser(testUserRep.getUsername());
+//    }
+//
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java
new file mode 100644
index 0000000..3ddf899
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.console.users;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.users.CreateUser;
+import org.keycloak.testsuite.console.page.users.Users;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractUserTest extends AbstractConsoleTest {
+
+    @Page
+    protected Users usersPage;
+    @Page
+    protected CreateUser createUserPage;
+
+    protected UserRepresentation newTestRealmUser;
+    
+    @Before
+    public void beforeUserTest() {
+        newTestRealmUser = new UserRepresentation();
+//        manage().users();
+    }
+
+    public void createUser(UserRepresentation user) {
+        assertCurrentUrlEquals(usersPage);
+        usersPage.table().addUser();
+        assertCurrentUrlStartsWith(createUserPage);
+        createUserPage.form().setValues(user);
+        createUserPage.form().save();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/RequiredUserActionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/RequiredUserActionsTest.java
new file mode 100644
index 0000000..9151698
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/RequiredUserActionsTest.java
@@ -0,0 +1,147 @@
+package org.keycloak.testsuite.console.users;
+
+import static org.jboss.arquillian.graphene.Graphene.waitGui;
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.account.Account;
+import org.keycloak.testsuite.auth.page.login.UpdateAccount;
+import org.keycloak.testsuite.auth.page.login.UpdatePassword;
+import org.keycloak.testsuite.console.page.authentication.RequiredActions;
+import org.keycloak.testsuite.console.page.users.UserAttributes;
+
+import static org.keycloak.testsuite.model.RequiredUserAction.TERMS_AND_CONDITIONS;
+import static org.keycloak.testsuite.model.RequiredUserAction.UPDATE_PASSWORD;
+import static org.keycloak.testsuite.model.RequiredUserAction.UPDATE_PROFILE;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class RequiredUserActionsTest extends AbstractUserTest {
+
+    @Page
+    private UserAttributes userAttributesPage;
+
+    @Page
+    private Account testRealmAccountPage;
+
+    @Page
+    private UpdateAccount testRealmUpdateAccountPage;
+
+    @Page
+    private UpdatePassword testRealmUpdatePasswordPage;
+
+    @Page
+    private RequiredActions requiredActionsPage;
+
+    @FindBy(css = "kc-feedback-text")
+    protected WebElement feedbackText;
+
+    public void waitForFeedbackText(String text) {
+        waitGui().until().element(By.className("kc-feedback-text"))
+                .text().contains(text);
+    }
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmAccountPage.setAuthRealm(TEST);
+        testRealmUpdateAccountPage.setAuthRealm(TEST);
+        testRealmUpdatePasswordPage.setAuthRealm(TEST);
+    }
+
+    @Before
+    public void beforeRequiredActionsTest() {
+//        usersPage.table().viewAllUsers();
+//        usersPage.table().clickUser(testUser.getUsername());
+        userAttributesPage.setId(testUser.getId());
+        userAttributesPage.navigateTo();
+    }
+
+    @Test
+    public void updatePassword() {
+        userAttributesPage.form().addRequiredAction(UPDATE_PASSWORD.getActionName());
+        userAttributesPage.form().save();
+        assertFlashMessageSuccess();
+
+        testRealmAccountPage.navigateTo();
+
+        testRealmLoginPage.form().login(testUser);
+        waitForFeedbackText("You need to change your password to activate your account.");
+
+        testRealmUpdatePasswordPage.updatePasswords(null, null);
+        waitForFeedbackText("Please specify password.");
+
+        testRealmUpdatePasswordPage.updatePasswords(PASSWORD, null);
+        waitForFeedbackText("Passwords don't match.");
+
+        testRealmUpdatePasswordPage.updatePasswords(PASSWORD, PASSWORD + "-mismatch");
+        waitForFeedbackText("Passwords don't match.");
+
+        testRealmUpdatePasswordPage.updatePasswords(PASSWORD, PASSWORD);
+        assertCurrentUrlStartsWith(testRealmAccountPage);
+    }
+
+    @Test
+    public void updateProfile() {
+        userAttributesPage.form().addRequiredAction(UPDATE_PROFILE.getActionName());
+        userAttributesPage.form().save();
+        assertFlashMessageSuccess();
+
+        testRealmAccountPage.navigateTo();
+
+        testRealmLoginPage.form().login(testUser);
+        waitForFeedbackText("You need to update your user profile to activate your account.");
+
+        testUser.setEmail(null);
+        testUser.setFirstName(null);
+        testUser.setLastName(null);
+        testRealmUpdateAccountPage.updateAccount(testUser);
+        waitForFeedbackText("Please specify email.");
+
+        testUser.setEmail("test@email.test");
+        testRealmUpdateAccountPage.updateAccount(testUser);
+        waitForFeedbackText("Please specify first name.");
+
+        testUser.setFirstName("test");
+        testRealmUpdateAccountPage.updateAccount(testUser);
+        waitForFeedbackText("Please specify last name.");
+
+        testUser.setLastName("user");
+        testRealmUpdateAccountPage.updateAccount(testUser);
+        assertCurrentUrlStartsWith(testRealmAccountPage);
+    }
+
+    @Test
+    public void termsAndConditions() {
+        requiredActionsPage.navigateTo();
+        requiredActionsPage.clickTermsAndConditionEnabled();
+
+        manage().users();
+        usersPage.table().viewAllUsers();
+        usersPage.table().clickUser(testUser.getUsername());
+
+        userAttributesPage.form().addRequiredAction(TERMS_AND_CONDITIONS.getActionName());
+        userAttributesPage.form().save();
+        assertFlashMessageSuccess();
+
+        testRealmAccountPage.navigateTo();
+
+        testRealmLoginPage.form().login(testUser);
+
+        driver.findElement(By.xpath("//div[@id='kc-header-wrapper' and text()[contains(.,'Terms and Conditions')]]"));
+    }
+
+
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UserAttributesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UserAttributesTest.java
new file mode 100644
index 0000000..9d99c85
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UserAttributesTest.java
@@ -0,0 +1,90 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.users;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import org.keycloak.testsuite.console.page.users.UserAttributes;
+
+/**
+ *
+ * @author Filip Kiss
+ * @author tkyjovsk
+ */
+public class UserAttributesTest extends AbstractUserTest {
+
+    @Page
+    private UserAttributes userAttributesPage;
+
+    @Before
+    public void beforeUserAttributesTest() {
+        usersPage.navigateTo();
+    }
+    
+    @Test
+    public void invalidEmail() {
+        String testUsername = "testUserInvEmail";
+        String invalidEmail = "user.redhat.com";
+        newTestRealmUser.setUsername(testUsername);
+        setPasswordFor(newTestRealmUser, "pass");
+        newTestRealmUser.setEmail(invalidEmail);
+        createUser(newTestRealmUser);
+        assertFlashMessageDanger();
+
+        userAttributesPage.backToUsersViaBreadcrumb();
+        assertNull(usersPage.table().findUser(testUsername));
+    }
+
+    @Test
+    public void noUsername() {
+        createUser(newTestRealmUser);
+        assertFlashMessageDanger();
+    }
+
+    @Test
+    public void existingUser() {
+        String testUsername = "test_duplicated_user";
+        newTestRealmUser.setUsername(testUsername);
+        createUser(newTestRealmUser);
+        assertFlashMessageSuccess();
+
+        userAttributesPage.backToUsersViaBreadcrumb();
+        assertNotNull(usersPage.table().findUser(testUsername));
+
+        UserRepresentation testUser2 = new UserRepresentation();
+        testUser2.setUsername(testUsername);
+        createUser(testUser2);
+        assertFlashMessageDanger();
+    }
+
+    @Test
+    public void disabledUser() {
+        UserRepresentation disabledUser = new UserRepresentation();
+        disabledUser.setEnabled(false);
+        disabledUser.setUsername("disabled_user");
+        createUser(disabledUser);
+        assertFlashMessageSuccess();
+        // TODO try to log in
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UsersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UsersTest.java
new file mode 100644
index 0000000..ed4000d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UsersTest.java
@@ -0,0 +1,52 @@
+package org.keycloak.testsuite.console.users;
+
+import javax.ws.rs.core.Response;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.getCreatedId;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.keycloak.testsuite.util.Timer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UsersTest extends AbstractUserTest {
+    
+    @Before
+    public void beforeUserAttributesTest() {
+        usersPage.navigateTo();
+    }
+    
+    public void createTestUsers(String usernamePrefix, int count) {
+//        Timer.time();
+        for (int i = 0; i < count; i++) {
+            String username = String.format("%s%03d", usernamePrefix, i);
+            UserRepresentation u = createUserRepresentation(
+                    username,
+                    username + "@email.test",
+                    "First",
+                    "Last",
+                    true);
+            Timer.time();
+            Response r = testRealmResource().users().create(u);
+            String id = getCreatedId(r);
+            r.close();
+            Timer.time("create user");
+        }
+//        Timer.time("create " + count + " users");
+    }
+    
+    @Test
+    @Ignore
+    public void usersPagination() {
+        createTestUsers("test_user_", 100);
+        
+        usersPage.navigateTo();
+        usersPage.table().viewAllUsers();
+        pause(120000);
+    }
+    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AttributesAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AttributesAssert.java
new file mode 100644
index 0000000..2974a90
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AttributesAssert.java
@@ -0,0 +1,42 @@
+package org.keycloak.testsuite.util;
+
+import java.util.List;
+import static org.junit.Assert.assertEquals;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AttributesAssert {
+
+    public static void assertEqualsStringAttributes(String a1, String a2) {
+        if (a1 == null) {
+            a1 = "";
+        }
+        if (a2 == null) {
+            a2 = "";
+        }
+        assertEquals(a1, a2);
+    }
+
+    public static void assertEqualsBooleanAttributes(Boolean a1, Boolean a2) {
+        if (a1 == null) {
+            a1 = false;
+        }
+        if (a2 == null) {
+            a2 = false;
+        }
+        assertEquals(a1, a2);
+    }
+
+    public static void assertEqualsListAttributes(List a1, List a2) {
+        if (a1 == null || a1.isEmpty()) {
+            a1 = null;
+        }
+        if (a2 == null || a2.isEmpty()) {
+            a2 = null;
+        }
+        assertEquals(a1, a2);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java
new file mode 100644
index 0000000..4ade10b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java
@@ -0,0 +1,54 @@
+package org.keycloak.testsuite.util;
+
+import java.io.IOException;
+import javax.mail.MessagingException;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMessage.RecipientType;
+import javax.mail.internet.MimeMultipart;
+import org.jboss.logging.Logger;
+import static org.junit.Assert.*;
+
+public class MailAssert {
+
+    private static final Logger log = Logger.getLogger(MailAssert.class);
+    
+    public static String assertEmailAndGetUrl(String from, String recipient, String content) {
+
+        try {
+            MimeMessage message = MailServer.getLastReceivedMessage();
+            assertNotNull("There is no received email.", message);
+            assertEquals(recipient, message.getRecipients(RecipientType.TO)[0].toString());
+            assertEquals(from, message.getFrom()[0].toString());
+
+            String messageContent;
+            if (message.getContent() instanceof MimeMultipart) {
+                MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
+
+                messageContent = String.valueOf(mimeMultipart.getBodyPart(0).getContent());
+            } else {
+                messageContent = String.valueOf(message.getContent());
+            }
+            logMessageContent(messageContent);
+            String errorMessage = "Email content should contains \"" + content
+                    + "\", but it doesn't.\nEmail content:\n" + messageContent + "\n";
+
+            assertTrue(errorMessage, messageContent.contains(content));
+            for (String string : messageContent.split("\n")) {
+                if (string.contains("http://")) {
+                    return string;
+                }
+            }
+            return null;
+        } catch (IOException | MessagingException | InterruptedException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private static void logMessageContent(String messageContent) {
+        log.debug("---------------------");
+        log.debug(messageContent);
+        log.debug("---------------------");
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java
new file mode 100644
index 0000000..972027d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java
@@ -0,0 +1,77 @@
+package org.keycloak.testsuite.util;
+
+import com.icegreen.greenmail.util.GreenMail;
+import com.icegreen.greenmail.util.ServerSetup;
+import java.io.IOException;
+import javax.mail.MessagingException;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMessage.RecipientType;
+import javax.mail.internet.MimeMultipart;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.util.MailServerConfiguration.*;
+
+public class MailServer {
+
+    private static final Logger log = Logger.getLogger(MailServer.class);
+    
+    private static GreenMail greenMail;
+
+    public static void main(String[] args) throws Exception {
+        MailServer.start();
+        MailServer.createEmailAccount("test@email.test", "password");
+        
+        try {
+            while (true) {
+                int c = greenMail.getReceivedMessages().length;
+
+                if (greenMail.waitForIncomingEmail(Long.MAX_VALUE, c + 1)) {
+                    MimeMessage m = greenMail.getReceivedMessages()[c++];
+                    log.info("-------------------------------------------------------");
+                    log.info("Received mail to " + m.getRecipients(RecipientType.TO)[0]);
+                    if (m.getContent() instanceof MimeMultipart) {
+                        MimeMultipart mimeMultipart = (MimeMultipart) m.getContent();
+                        for (int i = 0; i < mimeMultipart.getCount(); i++) {
+                            log.info("----");
+                            log.info(mimeMultipart.getBodyPart(i).getContentType() + ":\n");
+                            log.info(mimeMultipart.getBodyPart(i).getContent());
+                        }
+                    } else {
+                        log.info("\n" + m.getContent());
+                    }
+                    log.info("-------------------------------------------------------");
+                }
+            }
+        } catch (IOException | InterruptedException | MessagingException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public static void start() {
+        ServerSetup setup = new ServerSetup(Integer.parseInt(PORT), HOST, "smtp");
+
+        greenMail = new GreenMail(setup);
+        greenMail.start();
+
+        log.info("--Started mail server (" + HOST + ":" + PORT + ")--");
+    }
+
+    public static void stop() {
+        if (greenMail != null) {
+            log.info("--Stopping mail server (localhost:3025)--");
+            greenMail.stop();
+        }
+    }
+
+    public static void createEmailAccount(String email, String password) {
+        log.debug("--Creating email account " + email + "--");
+        greenMail.setUser(email, password);
+    }
+    
+    public static MimeMessage getLastReceivedMessage() throws InterruptedException {
+        if (greenMail.waitForIncomingEmail(1)) {
+            return greenMail.getReceivedMessages()[greenMail.getReceivedMessages().length - 1];
+        }
+        return null;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/TestEventsLogger.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/TestEventsLogger.java
new file mode 100644
index 0000000..249a19b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/TestEventsLogger.java
@@ -0,0 +1,44 @@
+package org.keycloak.testsuite.util;
+
+import org.jboss.logging.Logger;
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class TestEventsLogger extends RunListener {
+
+    private Logger log(Description d) {
+        return Logger.getLogger(d.getClassName());
+    }
+
+    private String getMessage(Description d, String status) {
+        return String.format("[%s] %s() %s", d.getTestClass().getSimpleName(), d.getMethodName(), status);
+    }
+
+    @Override
+    public void testStarted(Description d) throws Exception {
+        log(d).info(getMessage(d, "STARTED"));
+    }
+
+    @Override
+    public void testFailure(Failure f) throws Exception {
+        Description d = f.getDescription();
+        log(d).error(getMessage(d, "FAILED"));
+    }
+
+    @Override
+    public void testIgnored(Description d) throws Exception {
+        log(d).warn(getMessage(d, "IGNORED\n\n"));
+    }
+
+    @Override
+    public void testFinished(Description d) throws Exception {
+        log(d).info(getMessage(d, "FINISHED\n\n"));
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java
new file mode 100644
index 0000000..255e450
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java
@@ -0,0 +1,95 @@
+package org.keycloak.testsuite.util;
+
+import javax.ws.rs.core.UriBuilder;
+import org.keycloak.testsuite.page.AbstractPage;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class URLAssert {
+
+    public static void assertCurrentUrlEquals(AbstractPage page) {
+        assertCurrentUrlEquals(page.getDriver(), page);
+    }
+
+    public static void assertCurrentUrlEquals(WebDriver driver, final AbstractPage page) {
+//        WebDriverWait wait = new WebDriverWait(driver, 1);
+//        ExpectedCondition<Boolean> urlStartsWith = new ExpectedCondition<Boolean>() {
+//
+//            @Override
+//            public Boolean apply(WebDriver wd) {
+//                return startsWithNormalized(wd.getCurrentUrl(), page.toString());
+//            }
+//        };
+//        wait.until(urlStartsWith);
+        assertEqualsNormalized(driver.getCurrentUrl(), page.toString());
+    }
+
+    public static void assertCurrentUrlStartsWith(AbstractPage page) {
+        assertCurrentUrlStartsWith(page.getDriver(), page.toString());
+    }
+
+    public static void assertCurrentUrlStartsWith(WebDriver driver, final String url) {
+//        WebDriverWait wait = new WebDriverWait(driver, 1);
+//        ExpectedCondition<Boolean> urlStartsWith = new ExpectedCondition<Boolean>() {
+//
+//            @Override
+//            public Boolean apply(WebDriver wd) {
+//                return startsWithNormalized(wd.getCurrentUrl(), url);
+//            }
+//        };
+//        wait.until(urlStartsWith);
+        assertTrue(startsWithNormalized(driver.getCurrentUrl(), url));
+    }
+
+    public static void assertCurrentUrlDoesntStartWith(AbstractPage page) {
+        assertCurrentUrlDoesntStartWith(page.getDriver(), page.toString());
+    }
+
+    public static void assertCurrentUrlDoesntStartWith(WebDriver driver, final String url) {
+//        WebDriverWait wait = new WebDriverWait(driver, 1, 250);
+//        ExpectedCondition<Boolean> urlDoesntStartWith = new ExpectedCondition<Boolean>() {
+//
+//            @Override
+//            public Boolean apply(WebDriver wd) {
+//                return !startsWithNormalized(wd.getCurrentUrl(), url);
+//            }
+//        };
+//        wait.until(urlDoesntStartWith);
+        assertFalse(startsWithNormalized(driver.getCurrentUrl(), url));
+    }
+
+    // this normalization is needed because of slash-encoding in uri fragment (the part after #)
+    public static String normalizeUri(String uri) {
+        return UriBuilder.fromUri(uri).build().toASCIIString();
+    }
+
+    public static boolean startsWithNormalized(String str1, String str2) {
+        String uri1 = normalizeUri(str1);
+        String uri2 = normalizeUri(str2);
+        return uri1.startsWith(uri2);
+    }
+
+    public static void assertEqualsNormalized(String str1, String str2) {
+        assertEquals(normalizeUri(str1), normalizeUri(str2));
+    }
+
+
+
+    public static void assertCurrentUrlStartsWithLoginUrlOf(PageWithLoginUrl page) {
+        assertCurrentUrlStartsWithLoginUrlOf(page.getDriver(), page);
+    }
+    
+    public static void assertCurrentUrlStartsWithLoginUrlOf(WebDriver driver, PageWithLoginUrl page) {
+        assertCurrentUrlStartsWith(driver, page.getOIDCLoginUrl().toString());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/context.xml
new file mode 100644
index 0000000..ef49048
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/context.xml
@@ -0,0 +1,3 @@
+<Context path="/%CONTEXT_PATH%">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8180/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
new file mode 100644
index 0000000..3620170
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8180/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak-relative.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak-relative.json
new file mode 100644
index 0000000..c457468
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak-relative.json
@@ -0,0 +1,9 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "auth-server-url": "/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
new file mode 100644
index 0000000..8fbc2d2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>customer-db</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+    
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
new file mode 100644
index 0000000..aa10ca2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-db-error-page">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8180/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100644
index 0000000..3620170
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8180/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100644
index 0000000..496490d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>customer-db-error-page</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8180/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..b75c1d5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak.json
@@ -0,0 +1,11 @@
+{
+    "realm": "demo",
+    "resource": "customer-portal",
+    "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "auth-server-url": "http://localhost:8180/auth",
+    "ssl-required" : "external",
+    "expose-token": true,
+    "credentials": {
+        "secret": "password"
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-cookie.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-cookie.json
new file mode 100644
index 0000000..9d59c69
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-cookie.json
@@ -0,0 +1,12 @@
+{
+    "realm": "demo",
+    "resource": "customer-cookie-portal",
+    "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "auth-server-url": "http://localhost:8180/auth",
+    "ssl-required" : "external",
+    "expose-token": true,
+    "token-store": "cookie",
+    "credentials": {
+        "secret": "password"
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-relative.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-relative.json
new file mode 100644
index 0000000..a796d1a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-relative.json
@@ -0,0 +1,9 @@
+{
+    "realm": "demo",
+    "resource": "customer-portal",
+    "auth-server-url": "/auth",
+    "ssl-required" : "external",
+    "credentials": {
+        "secret": "password"
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..285d226
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>customer-portal</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.CustomerServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
new file mode 100644
index 0000000..5b82ec6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
@@ -0,0 +1,161 @@
+{
+    "id": "demo",
+    "realm": "demo",
+    "enabled": true,
+    "accessTokenLifespan": 3000,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 6000,
+    "sslRequired": "external",
+    "registrationAllowed": false,
+    "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" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "firstName": "Bill",
+            "lastName": "Burke",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "realmRoles": [ "user", "admin" ],
+            "applicationRoles": {
+                "account": [ "manage-account" ]
+            }
+        },
+        {
+            "username" : "mposolda",
+            "enabled": true,
+            "email" : "mposolda@redhat.com",
+            "firstName": "Marek",
+            "lastName": "Posolda",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": [ "user" ],
+            "applicationRoles": {
+                "account": [ "manage-account" ]
+            }
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "User privileges"
+            },
+            {
+                "name": "admin",
+                "description": "Administrator privileges"
+            }
+        ]
+    },
+    "scopeMappings": [
+        {
+            "client": "third-party",
+            "roles": ["user"]
+        },
+        {
+            "client": "customer-portal",
+            "roles": ["user"]
+        },
+        {
+            "client": "product-portal",
+            "roles": ["user"]
+        }
+
+    ],
+    "clients": [
+        {
+            "clientId": "customer-portal",
+            "enabled": true,
+            "adminUrl": "/customer-portal",
+            "baseUrl": "/customer-portal",
+            "redirectUris": [
+                "/customer-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "clientId": "customer-cookie-portal",
+            "enabled": true,
+            "baseUrl": "/customer-cookie-portal",
+            "redirectUris": [
+                "/customer-cookie-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "clientId": "customer-portal-js",
+            "enabled": true,
+            "publicClient": true,
+            "adminUrl": "/customer-portal-js",
+            "baseUrl": "/customer-portal-js",
+            "redirectUris": [
+                "/customer-portal-js/*"
+            ]
+        },
+        {
+            "clientId": "customer-portal-cli",
+            "enabled": true,
+            "publicClient": true,
+            "redirectUris": [
+                "urn:ietf:wg:oauth:2.0:oob",
+                "http://localhost"
+            ]
+        },
+        {
+            "clientId": "product-portal",
+            "enabled": true,
+            "adminUrl": "/product-portal",
+            "baseUrl": "/product-portal",
+            "redirectUris": [
+                "/product-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "clientId": "secure-portal",
+            "enabled": true,
+            "adminUrl": "/secure-portal",
+            "baseUrl": "/secure-portal",
+            "redirectUris": [
+                "/secure-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "clientId": "session-portal",
+            "enabled": true,
+            "adminUrl": "/session-portal",
+            "baseUrl": "/session-portal",
+            "redirectUris": [
+                "/session-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "clientId": "input-portal",
+            "enabled": true,
+            "adminUrl": "/input-portal",
+            "baseUrl": "/input-portal",
+            "redirectUris": [
+                "/input-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "clientId": "third-party",
+            "enabled": true,
+            "redirectUris": [
+                "/oauth-client/*",
+                "/oauth-client-cdi/*"
+            ],
+            "secret": "password"
+        }
+    ]
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8180/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..a934e97
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "input-portal",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://${my.host.name}:8180/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..81c4e28
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>input-portal</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/secured/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
new file mode 100644
index 0000000..af5341b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
@@ -0,0 +1,16 @@
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <!-- the Demo code uses classes in these modules.  These are optional to import if you are not using
+            Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
+            <module name="org.apache.httpcomponents"/>
+
+            <!--These are needed when keycloak adapter libs are bundled in war.-->
+            <module name="org.codehaus.jackson.jackson-xc" />
+            <module name="org.codehaus.jackson.jackson-mapper-asl" />
+            <module name="org.bouncycastle" />
+            <module name="org.jboss.xnio" />
+            
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant1-keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant1-keycloak.json
new file mode 100644
index 0000000..14b3f7b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant1-keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "tenant1",
+  "resource" : "multi-tenant",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8180/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant2-keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant2-keycloak.json
new file mode 100644
index 0000000..bfb1814
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant2-keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "tenant2",
+  "resource" : "multi-tenant",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8180/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/web.xml
new file mode 100644
index 0000000..6f830ae
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/web.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>multi-tenant</module-name>
+
+    <servlet>
+        <servlet-name>MultiTenantServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.MultiTenantServlet</servlet-class>
+    </servlet>
+    
+    <context-param>
+        <param-name>keycloak.config.resolver</param-name>
+        <param-value>org.keycloak.testsuite.adapter.servlet.MultiTenantResolver</param-value>
+    </context-param>
+    
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+    </login-config>
+
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+    
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8180/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..7dbe680
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "product-portal",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8180/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak-relative.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak-relative.json
new file mode 100644
index 0000000..9ef62ff
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak-relative.json
@@ -0,0 +1,9 @@
+{
+  "realm" : "demo",
+  "resource" : "product-portal",
+  "auth-server-url" : "/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..ebefac0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>product-portal</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.ProductServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8180/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..6b8d13f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "secure-portal",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8180/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..4ee9cd1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>secure-portal</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.CallAuthenticatedServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8180/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..d07b738
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "session-portal",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://${my.host.name}:8180/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..da08586
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>session-portal</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.SessionServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant1-realm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant1-realm.json
new file mode 100644
index 0000000..b565c05
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant1-realm.json
@@ -0,0 +1,82 @@
+{
+    "id": "tenant1",
+    "realm": "tenant1",
+    "enabled": true,
+    "accessTokenLifespan": 3000,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 6000,
+    "sslRequired": "external",
+    "registrationAllowed": false,
+    "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" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "firstName": "Bill",
+            "lastName": "Burke",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "realmRoles": [ "user" ],
+            "applicationRoles": {
+                "multi-tenant": [ "user" ]
+            }
+        },
+        {
+            "username" : "user-tenant1",
+            "enabled": true,
+            "email" : "user-tenant1@redhat.com",
+            "firstName": "Bill",
+            "lastName": "Burke",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "user-tenant1" }
+            ],
+            "realmRoles": [ "user" ],
+            "applicationRoles": {
+                "multi-tenant": [ "user" ]
+            }
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "User privileges"
+            }
+        ]
+    },
+    "scopeMappings": [
+        {
+            "client": "multi-tenant",
+            "roles": ["user"]
+        }
+
+    ],
+    "clients": [
+        {
+            "clientId": "multi-tenant",
+            "enabled": true,
+            "adminUrl": "/multi-tenant",
+            "baseUrl": "/multi-tenant",
+            "redirectUris": [
+                "/multi-tenant/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "clientId": "multitenant",
+            "enabled": true,
+            "adminUrl": "/multitenant/tenant1",
+            "baseUrl": "/multitenant/tenant1",
+            "redirectUris": [
+                "/multitenant/tenant1/*"
+            ],
+            "secret": "password"
+        }
+    ]
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant2-realm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant2-realm.json
new file mode 100644
index 0000000..54b28a4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant2-realm.json
@@ -0,0 +1,72 @@
+{
+    "id": "tenant2",
+    "realm": "tenant2",
+    "enabled": true,
+    "accessTokenLifespan": 3000,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 6000,
+    "sslRequired": "external",
+    "registrationAllowed": false,
+    "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" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "firstName": "Bill",
+            "lastName": "Burke",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "realmRoles": [ "user" ],
+            "applicationRoles": {
+                "multi-tenant": [ "user" ]
+            }
+        },
+        {
+            "username" : "user-tenant2",
+            "enabled": true,
+            "email" : "user-tenant2@redhat.com",
+            "firstName": "Bill",
+            "lastName": "Burke",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "user-tenant2" }
+            ],
+            "realmRoles": [ "user" ],
+            "applicationRoles": {
+                "multi-tenant": [ "user" ]
+            }
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "User privileges"
+            }
+        ]
+    },
+    "scopeMappings": [
+        {
+            "client": "multi-tenant",
+            "roles": ["user"]
+        }
+
+    ],
+    "clients": [
+        {
+            "clientId": "multi-tenant",
+            "enabled": true,
+            "adminUrl": "/multi-tenant",
+            "baseUrl": "/multi-tenant",
+            "redirectUris": [
+                "/multi-tenant/*"
+            ],
+            "secret": "password"
+        }
+    ]
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/web.xml
new file mode 100644
index 0000000..1b6dc5e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/web.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>%CONTEXT_PATH%</module-name>
+
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
new file mode 100644
index 0000000..7b2713e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
@@ -0,0 +1,91 @@
+<arquillian xmlns="http://jboss.org/schema/arquillian"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://jboss.org/schema/arquillian
+        http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
+
+    <defaultProtocol type="Servlet 3.0" />
+	
+    <extension qualifier="webdriver">
+        <property name="browser">${browser}</property>
+    </extension>
+    
+    <extension qualifier="graphene-secondbrowser">
+        <property name="browser">${browser}</property>
+    </extension>
+    
+    <engine>
+        <!-- This allows manual inspection of deployed archives. -->
+        <property name="deploymentExportPath">target/deployments</property>
+    </engine>
+    
+    <!-- PREVIOUS VERSIONS KEYCLOAK FOR MIGRATION TESTS -->
+    <!-- IT HAS TO BE LISTED ABOWE KEYCLOAK AUTH SERVERS -->
+    
+    <container qualifier="keycloak-1.4.0.Final" mode="suite" >
+        <configuration>
+            <property name="enabled">${migration.kc14}</property>
+            <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+            <property name="jbossHome">${keycloak-1.4.0.Final.home}</property>
+            <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
+            <property name="managementPort">${auth.server.management.port}</property>
+            <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+        </configuration>
+    </container>
+    
+    <container qualifier="keycloak-1.3.1.Final" mode="suite" >
+        <configuration>
+            <property name="enabled">${migration.kc13}</property>
+            <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+            <property name="jbossHome">${keycloak-1.3.1.Final.home}</property>
+            <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
+            <property name="managementPort">${auth.server.management.port}</property>
+            <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+        </configuration>
+    </container>
+    
+    <container qualifier="keycloak-1.2.0.Final" mode="suite" >
+        <configuration>
+            <property name="enabled">${migration.kc12}</property>
+            <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+            <property name="jbossHome">${keycloak-1.2.0.Final.home}</property>
+            <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
+            <property name="managementPort">${auth.server.management.port}</property>
+            <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+        </configuration>
+    </container>
+    
+    <!-- KEYCLOAK AUTH SERVERS -->
+    
+    <container qualifier="auth-server-undertow" mode="suite" >
+        <configuration>
+            <property name="enabled">${auth.server.undertow}</property>
+            <property name="bindAddress">localhost</property>
+            <property name="adapterImplClass">org.keycloak.testsuite.arquillian.undertow.CustomUndertowContainer</property>
+            <property name="bindHttpPort">${auth.server.http.port}</property>
+        </configuration>
+    </container>
+    
+    <container qualifier="auth-server-wildfly" mode="suite" >
+        <configuration>
+            <property name="enabled">${auth.server.wildfly}</property>
+            <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+            <property name="jbossHome">${auth.server.wildfly.home}</property>
+            <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+            <property name="managementPort">${auth.server.management.port}</property>
+            <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+        </configuration>
+    </container>
+    
+    <container qualifier="auth-server-eap6" mode="suite" >
+        <configuration>
+            <property name="enabled">${auth.server.eap6}</property>
+            <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+            <property name="jbossHome">${auth.server.eap6.home}</property>
+            <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+            <property name="managementAddress">localhost</property>
+            <property name="managementPort">${auth.server.management.port.jmx}</property>
+            <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+        </configuration>
+    </container>
+    
+</arquillian>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties b/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties
new file mode 100644
index 0000000..50dab50
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties
@@ -0,0 +1,43 @@
+log4j.rootLogger=info, keycloak
+
+log4j.appender.keycloak=org.apache.log4j.ConsoleAppender
+log4j.appender.keycloak.layout=org.apache.log4j.PatternLayout
+log4j.appender.keycloak.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
+
+log4j.appender.testsuite=org.apache.log4j.ConsoleAppender
+log4j.appender.testsuite.layout=org.apache.log4j.PatternLayout
+log4j.appender.testsuite.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %m%n
+
+log4j.logger.org.keycloak=off, keycloak
+
+log4j.logger.org.keycloak.testsuite=debug, testsuite
+log4j.additivity.org.keycloak.testsuite=false
+
+# Enable to view events
+# log4j.logger.org.keycloak.events=debug
+
+# Enable to view loaded SPI and Providers
+# log4j.logger.org.keycloak.services.DefaultKeycloakSessionFactory=debug
+# log4j.logger.org.keycloak.provider.ProviderManager=debug
+# log4j.logger.org.keycloak.provider.FileSystemProviderLoaderFactory=debug
+
+# Liquibase updates logged with "info" by default. Logging level can be changed by system property "keycloak.liquibase.logging.level"
+keycloak.liquibase.logging.level=info
+log4j.logger.org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider=${keycloak.liquibase.logging.level}
+
+# Enable to view database updates
+# log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
+# log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
+# log4j.logger.org.keycloak.migration.MigrationModelManager=debug
+
+# Enable to view kerberos/spnego logging
+# log4j.logger.org.keycloak.broker.kerberos=trace
+
+# Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server
+# log4j.logger.org.apache.directory.server.kerberos=debug
+
+log4j.logger.org.xnio=off
+log4j.logger.org.hibernate=off
+log4j.logger.org.jboss.resteasy=warn
+log4j.logger.org.apache.directory.api=warn
+log4j.logger.org.apache.directory.server.core=warn
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
new file mode 100644
index 0000000..c760152
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
@@ -0,0 +1,99 @@
+{
+    "admin": {
+        "realm": "master"
+    },
+
+    "eventsStore": {
+        "provider": "${keycloak.eventsStore.provider:jpa}"
+    },
+
+    "eventsListener": {
+        "jboss-logging" : {
+            "success-level": "debug",
+            "error-level": "warn"
+        }
+    },
+
+    "realm": {
+        "provider": "${keycloak.realm.provider:jpa}"
+    },
+
+    "user": {
+        "provider": "${keycloak.user.provider:jpa}"
+    },
+
+    "userSessions": {
+        "provider" : "${keycloak.userSessions.provider:infinispan}"
+    },
+
+    "realmCache": {
+        "provider": "${keycloak.realm.cache.provider:infinispan}"
+    },
+
+    "userCache": {
+        "provider": "${keycloak.user.cache.provider:infinispan}",
+        "mem": {
+            "maxSize": 20000
+        }
+    },
+
+    "timer": {
+        "provider": "basic"
+    },
+
+    "theme": {
+        "default": "keycloak",
+        "staticMaxAge": "${keycloak.theme.staticMaxAge:2592000}",
+        "cacheTemplates": "${keycloak.theme.cacheTemplates:true}",
+        "cacheThemes": "${keycloak.theme.cacheThemes:true}",
+        "folder": {
+            "dir": "${keycloak.theme.dir}"
+        }
+    },
+
+    "login": {
+        "provider": "freemarker"
+    },
+
+    "account": {
+        "provider": "freemarker"
+    },
+
+    "email": {
+        "provider": "freemarker"
+    },
+
+    "scheduled": {
+        "interval": 900
+    },
+
+    "connectionsHttpClient": {
+        "default": {
+            "disable-trust-manager": true
+        }
+    },
+
+
+    "connectionsJpa": {
+        "default": {
+            "url": "${keycloak.connectionsJpa.url:jdbc:h2:mem:test}",
+            "driver": "${keycloak.connectionsJpa.driver:org.h2.Driver}",
+            "driverDialect": "${keycloak.connectionsJpa.driverDialect:}",
+            "user": "${keycloak.connectionsJpa.user:sa}",
+            "password": "${keycloak.connectionsJpa.password:}",
+            "databaseSchema": "${keycloak.connectionsJpa.databaseSchema:update}",
+            "showSql": "${keycloak.connectionsJpa.showSql:false}",
+            "formatSql": "${keycloak.connectionsJpa.formatSql:true}"
+        }
+    },
+
+    "connectionsMongo": {
+        "default": {
+            "host": "${keycloak.connectionsMongo.host:127.0.0.1}",
+            "port": "${keycloak.connectionsMongo.port:27017}",
+            "db": "${keycloak.connectionsMongo.db:keycloak}",
+            "databaseSchema": "${keycloak.connectionsMongo.databaseSchema:update}",
+            "connectionsPerHost": "${keycloak.connectionsMongo.connectionsPerHost:100}"
+        }
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
new file mode 100644
index 0000000..2dd55cf
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -0,0 +1,597 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian</artifactId>
+        <version>1.6.0.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-tests</artifactId>
+    <packaging>pom</packaging>
+    <name>Tests</name>
+    
+    <modules>
+        <module>base</module>
+        <module>adapters</module>
+    </modules>
+    
+    <properties>
+        <containers.home>${project.build.directory}/containers</containers.home>
+        <examples.home>${project.build.directory}/examples</examples.home>
+
+        <auth.server.container>auth-server-undertow</auth.server.container>
+        <auth.server.port.offset>100</auth.server.port.offset>
+        <auth.server.http.port>8180</auth.server.http.port>
+        <auth.server.management.port>10090</auth.server.management.port>
+        <auth.server.management.port.jmx>10099</auth.server.management.port.jmx>
+        <startup.timeout.sec>60</startup.timeout.sec>
+        
+        <browser>phantomjs</browser>
+
+        <arquillian-core.version>1.1.8.Final</arquillian-core.version>
+        <selenium.version>2.45.0</selenium.version>
+        <arquillian-drone.version>2.0.0.Alpha4</arquillian-drone.version>
+        <arquillian-graphene.version>2.1.0.Alpha2</arquillian-graphene.version>
+        <arquillian-wildfly-container.version>8.2.0.Final</arquillian-wildfly-container.version>
+        <version.shrinkwrap.resolvers>2.1.1</version.shrinkwrap.resolvers>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.jboss.arquillian.selenium</groupId>
+                <artifactId>selenium-bom</artifactId>
+                <version>${selenium.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.jboss.arquillian</groupId>
+                <artifactId>arquillian-bom</artifactId>
+                <version>${arquillian-core.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.jboss.arquillian.extension</groupId>
+                <artifactId>arquillian-drone-bom</artifactId>
+                <version>${arquillian-drone.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.wildfly</groupId>
+                <artifactId>wildfly-arquillian-container-managed</artifactId>
+                <version>${arquillian-wildfly-container.version}</version>
+            </dependency>        
+        </dependencies>
+    </dependencyManagement>
+    
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <configuration>
+                        <systemPropertyVariables>
+                            <browser>${browser}</browser>
+                            <shouldDeploy>false</shouldDeploy>
+                            <auth.server.container>${auth.server.container}</auth.server.container>
+                            <auth.server.undertow>true</auth.server.undertow>
+                            <auth.server.port.offset>${auth.server.port.offset}</auth.server.port.offset>
+                            <auth.server.http.port>${auth.server.http.port}</auth.server.http.port>
+                            <auth.server.management.port>${auth.server.management.port}</auth.server.management.port>
+                            <auth.server.management.port.jmx>${auth.server.management.port.jmx}</auth.server.management.port.jmx>
+                            <startup.timeout.sec>${startup.timeout.sec}</startup.timeout.sec>
+                        </systemPropertyVariables>
+                        <properties>
+                            <property>
+                                <name>listener</name>
+                                <value>org.keycloak.testsuite.util.TestEventsLogger</value>
+                            </property>
+                        </properties>
+                        <failIfNoTests>false</failIfNoTests>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>        
+    </build>
+
+    <profiles>
+        
+        <profile>
+            <id>common-for-tests</id>
+            <activation>
+                <file>
+                    <exists>src</exists>
+                    <!--    ^ only activate this profile in submodules that have actual tests -->
+                </file>
+            </activation>
+            <dependencies>
+                <!-- TEST DEPENDENCIES -->
+                <dependency>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.arquillian.junit</groupId>
+                    <artifactId>arquillian-junit-container</artifactId>
+                </dependency>
+
+                <dependency>
+                    <groupId>org.jboss.arquillian.graphene</groupId>
+                    <artifactId>graphene-webdriver</artifactId>
+                    <version>${arquillian-graphene.version}</version>
+                    <type>pom</type>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.arquillian.protocol</groupId>
+                    <artifactId>arquillian-protocol-servlet</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.arquillian.extension</groupId>
+                    <artifactId>arquillian-phantom-driver</artifactId>
+                </dependency>
+                <!-- TODO: investigate if we need this dependency
+                <dependency>
+                    <groupId>org.jboss.arquillian.graphene</groupId>
+                    <artifactId>arquillian-graphene-impl</artifactId>
+                    <version>1.0.0.CR3</version>
+                </dependency>-->
+                <dependency>
+                    <groupId>org.jboss.arquillian.graphene</groupId>
+                    <artifactId>arquillian-browser-screenshooter</artifactId>
+                    <version>2.1.0.Alpha2</version>
+                </dependency>
+                
+                <dependency>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </dependency>
+
+                <dependency>
+                    <groupId>javax.servlet</groupId>
+                    <artifactId>javax.servlet-api</artifactId>
+                    <version>3.1.0</version>
+                </dependency>
+
+                <dependency>
+                    <groupId>org.apache.ant</groupId>
+                    <artifactId>ant</artifactId>
+                    <version>1.9.2</version>
+                    <type>jar</type>
+                </dependency>
+        
+                <!-- Email Test Server -->
+                <dependency>
+                    <groupId>com.icegreen</groupId>
+                    <artifactId>greenmail</artifactId>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>org.slf4j</groupId>
+                            <artifactId>slf4j-api</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+                        
+                <!-- Keycloak deps for tests -->
+
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-dependencies-server-all</artifactId>
+                    <type>pom</type>
+                </dependency>
+
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-core</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-admin-client</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-services</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-adapter-core</artifactId>
+                </dependency>
+
+
+                <!-- Keycloak Server on Undertow -->
+
+                <dependency>
+                    <groupId>org.jboss.arquillian.container</groupId>
+                    <artifactId>undertow-embedded</artifactId>
+                    <version>1.0.0.Alpha1-SNAPSHOT</version>
+                </dependency>
+        
+                <dependency>
+                    <groupId>org.jboss.resteasy</groupId>
+                    <artifactId>jaxrs-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.resteasy</groupId>
+                    <artifactId>async-http-servlet-3.0</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.resteasy</groupId>
+                    <artifactId>resteasy-jaxrs</artifactId>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>log4j</groupId>
+                            <artifactId>log4j</artifactId>
+                        </exclusion>
+                        <exclusion>
+                            <groupId>org.slf4j</groupId>
+                            <artifactId>slf4j-api</artifactId>
+                        </exclusion>
+                        <exclusion>
+                            <groupId>org.slf4j</groupId>
+                            <artifactId>slf4j-simple</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.resteasy</groupId>
+                    <artifactId>resteasy-client</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.resteasy</groupId>
+                    <artifactId>resteasy-undertow</artifactId>
+                    <scope>compile</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.resteasy</groupId>
+                    <artifactId>resteasy-multipart-provider</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.resteasy</groupId>
+                    <artifactId>resteasy-jackson-provider</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.codehaus.jackson</groupId>
+                    <artifactId>jackson-core-asl</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.codehaus.jackson</groupId>
+                    <artifactId>jackson-mapper-asl</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.codehaus.jackson</groupId>
+                    <artifactId>jackson-xc</artifactId>
+                </dependency>
+        
+                <dependency>
+                    <groupId>org.hibernate.javax.persistence</groupId>
+                    <artifactId>hibernate-jpa-2.1-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.h2database</groupId>
+                    <artifactId>h2</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.hibernate</groupId>
+                    <artifactId>hibernate-entitymanager</artifactId>
+                </dependency>
+
+                <dependency>
+                    <groupId>org.bouncycastle</groupId>
+                    <artifactId>bcprov-jdk15on</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.bouncycastle</groupId>
+                    <artifactId>bcpkix-jdk15on</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.hamcrest</groupId>
+                    <artifactId>hamcrest-all</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.infinispan</groupId>
+                    <artifactId>infinispan-core</artifactId>
+                </dependency>
+                
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>               
+                    </plugin> 
+                </plugins>
+            </build>            
+        </profile>
+        
+        <profile>
+            <id>auth-server-wildfly</id>
+            <properties>
+                <auth.server.container>auth-server-wildfly</auth.server.container>
+                <auth.server.wildfly.home>${containers.home}/keycloak-${project.version}</auth.server.wildfly.home>
+                <startup.timeout.sec>150</startup.timeout.sec>
+                <adapter.test.props/>
+            </properties>
+            <dependencies>
+                <dependency>
+                    <groupId>org.wildfly</groupId>
+                    <artifactId>wildfly-arquillian-container-managed</artifactId>
+                </dependency>                 
+            </dependencies>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-dependency-plugin</artifactId>
+                            <version>2.10</version>
+                            <executions>
+                                <execution>
+                                    <id>unpack</id>
+                                    <phase>generate-test-resources</phase>
+                                    <goals>
+                                        <goal>unpack</goal>
+                                    </goals>
+                                    <configuration>
+                                        <artifactItems>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>integration-arquillian-server-wildfly</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>zip</type>
+                                            </artifactItem>
+                                        </artifactItems>
+                                        <outputDirectory>${containers.home}</outputDirectory>
+                                        <overWriteIfNewer>true</overWriteIfNewer>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <auth.server.wildfly>true</auth.server.wildfly>
+                                    <auth.server.undertow>false</auth.server.undertow>
+                                    <auth.server.wildfly.home>${auth.server.wildfly.home}</auth.server.wildfly.home>
+                                    <adapter.test.props>${adapter.test.props}</adapter.test.props>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+        
+        <profile>
+            <id>auth-server-eap6</id>
+            <properties>
+                <auth.server.container>auth-server-eap6</auth.server.container>
+                <auth.server.eap6.home>${containers.home}/keycloak-${project.version}</auth.server.eap6.home>
+                <startup.timeout.sec>150</startup.timeout.sec>
+                <adapter.test.props/>
+            </properties>
+            <dependencies>
+                <dependency>
+                    <groupId>org.jboss.as</groupId>
+                    <artifactId>jboss-as-arquillian-container-managed</artifactId>
+                    <version>7.2.0.Final</version>
+                </dependency>
+            </dependencies>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-dependency-plugin</artifactId>
+                            <version>2.10</version>
+                            <executions>
+                                <execution>
+                                    <id>unpack</id>
+                                    <phase>generate-test-resources</phase>
+                                    <goals>
+                                        <goal>unpack</goal>
+                                    </goals>
+                                    <configuration>
+                                        <artifactItems>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>integration-arquillian-server-eap6</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>zip</type>
+                                            </artifactItem>
+                                        </artifactItems>
+                                        <outputDirectory>${containers.home}</outputDirectory>
+                                        <overWriteIfNewer>true</overWriteIfNewer>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <auth.server.eap6>true</auth.server.eap6>
+                                    <auth.server.undertow>false</auth.server.undertow>
+                                    <auth.server.eap6.home>${auth.server.eap6.home}</auth.server.eap6.home>
+                                    <adapter.test.props>${adapter.test.props}</adapter.test.props>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+        
+        <!-- Profiles for migration tests-->
+        
+        <profile>
+            <id>migration-kc14</id>
+            <properties>
+                <keycloak-1.4.0.Final.home>${containers.home}/keycloak-1.4.0.Final</keycloak-1.4.0.Final.home>
+            </properties>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-dependency-plugin</artifactId>
+                            <version>2.10</version>
+                            <executions>
+                                <execution>
+                                    <id>unpack-previous</id>
+                                    <phase>generate-test-resources</phase>
+                                    <goals>
+                                        <goal>unpack</goal>
+                                    </goals>
+                                    <configuration>
+                                        <artifactItems>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>integration-arquillian-server-wildfly-kc14</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>zip</type>
+                                            </artifactItem>
+                                        </artifactItems>
+                                        <outputDirectory>${containers.home}</outputDirectory>
+                                        <overWriteIfNewer>true</overWriteIfNewer>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <migration>true</migration>
+                                    <migration.kc14>true</migration.kc14>
+                                    <keycloak-1.4.0.Final.home>${keycloak-1.4.0.Final.home}</keycloak-1.4.0.Final.home>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+        
+        <profile>
+            <id>migration-kc13</id>
+            <properties>
+                <keycloak-1.3.1.Final.home>${containers.home}/keycloak-1.3.1.Final</keycloak-1.3.1.Final.home>
+            </properties>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-dependency-plugin</artifactId>
+                            <version>2.10</version>
+                            <executions>
+                                <execution>
+                                    <id>unpack-previous</id>
+                                    <phase>generate-test-resources</phase>
+                                    <goals>
+                                        <goal>unpack</goal>
+                                    </goals>
+                                    <configuration>
+                                        <artifactItems>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>integration-arquillian-server-wildfly-kc13</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>zip</type>
+                                            </artifactItem>
+                                        </artifactItems>
+                                        <outputDirectory>${containers.home}</outputDirectory>
+                                        <overWriteIfNewer>true</overWriteIfNewer>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <migration>true</migration>
+                                    <migration.kc13>true</migration.kc13>
+                                    <keycloak-1.3.1.Final.home>${keycloak-1.3.1.Final.home}</keycloak-1.3.1.Final.home>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+        
+        <profile>
+            <id>migration-kc12</id>
+            <properties>
+                <keycloak-1.2.0.Final.home>${containers.home}/keycloak-1.2.0.Final</keycloak-1.2.0.Final.home>
+            </properties>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-dependency-plugin</artifactId>
+                            <version>2.10</version>
+                            <executions>
+                                <execution>
+                                    <id>unpack-previous</id>
+                                    <phase>generate-test-resources</phase>
+                                    <goals>
+                                        <goal>unpack</goal>
+                                    </goals>
+                                    <configuration>
+                                        <artifactItems>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>integration-arquillian-server-wildfly-kc12</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>zip</type>
+                                            </artifactItem>
+                                        </artifactItems>
+                                        <outputDirectory>${containers.home}</outputDirectory>
+                                        <overWriteIfNewer>true</overWriteIfNewer>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <migration>true</migration>
+                                    <migration.kc12>true</migration.kc12>
+                                    <keycloak-1.2.0.Final.home>${keycloak-1.2.0.Final.home}</keycloak-1.2.0.Final.home>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+    </profiles>
+    
+</project>