keycloak-aplcache

merge conflicts

9/23/2015 10:01:47 PM

Changes

core/pom.xml 5(+0 -5)

pom.xml 112(+53 -59)

services/pom.xml 25(+0 -25)

services/src/main/java/org/keycloak/services/managers/HttpAuthenticationChallenge.java 11(+0 -11)

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/LoginSettingsPage.java 63(+0 -63)

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

diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
index 8e4d163..24b56bb 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
@@ -240,6 +240,7 @@ public class SAMLEndpoint {
                         .relayState(relayState);
             if (config.isWantAuthnRequestsSigned()) {
                 binding.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
+                        .signatureAlgorithm(provider.getSignatureAlgorithm())
                         .signDocument();
             }
             try {
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 6d87d96..e28aa97 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -37,6 +37,7 @@ import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
 import org.keycloak.saml.SAML2AuthnRequestBuilder;
 import org.keycloak.saml.SAML2LogoutRequestBuilder;
 import org.keycloak.saml.SAML2NameIDPolicyBuilder;
+import org.keycloak.saml.SignatureAlgorithm;
 import org.keycloak.saml.common.constants.GeneralConstants;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 
@@ -108,6 +109,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
                 KeyPair keypair = new KeyPair(publicKey, privateKey);
 
                 binding.signWith(keypair);
+                binding.signatureAlgorithm(getSignatureAlgorithm());
                 binding.signDocument();
             }
 
@@ -201,6 +203,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
                 .relayState(userSession.getId());
         if (getConfig().isWantAuthnRequestsSigned()) {
             binding.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
+                    .signatureAlgorithm(getSignatureAlgorithm())
                     .signDocument();
         }
         return binding;
@@ -250,4 +253,14 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
                 "</EntityDescriptor>\n";
         return Response.ok(descriptor, MediaType.APPLICATION_XML_TYPE).build();
     }
+
+    public SignatureAlgorithm getSignatureAlgorithm() {
+        String alg = getConfig().getSignatureAlgorithm();
+        if (alg != null) {
+            SignatureAlgorithm algorithm = SignatureAlgorithm.valueOf(alg);
+            if (algorithm != null) return algorithm;
+        }
+        return SignatureAlgorithm.RSA_SHA256;
+    }
+
 }
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
index ad11be3..6ab3963 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
@@ -87,6 +87,14 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
         getConfig().put("wantAuthnRequestsSigned", String.valueOf(wantAuthnRequestsSigned));
     }
 
+    public String getSignatureAlgorithm() {
+        return getConfig().get("signatureAlgorithm");
+    }
+
+    public void setSignatureAlgorithm(String signatureAlgorithm) {
+        getConfig().put("signatureAlgorithm", signatureAlgorithm);
+    }
+
     public String getEncryptionPublicKey() {
         return getConfig().get("encryptionPublicKey");
     }
diff --git a/connections/jpa/pom.xml b/connections/jpa/pom.xml
index b36b850..0a99ed2 100755
--- a/connections/jpa/pom.xml
+++ b/connections/jpa/pom.xml
@@ -24,7 +24,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/connections/jpa/src/main/resources/META-INF/persistence.xml b/connections/jpa/src/main/resources/META-INF/persistence.xml
index 7a55d1e..f8f33be 100755
--- a/connections/jpa/src/main/resources/META-INF/persistence.xml
+++ b/connections/jpa/src/main/resources/META-INF/persistence.xml
@@ -29,6 +29,8 @@
         <class>org.keycloak.models.jpa.entities.AuthenticationExecutionEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticatorConfigEntity</class>
         <class>org.keycloak.models.jpa.entities.RequiredActionProviderEntity</class>
+        <class>org.keycloak.models.jpa.entities.OfflineUserSessionEntity</class>
+        <class>org.keycloak.models.jpa.entities.OfflineClientSessionEntity</class>
 
         <!-- JpaAuditProviders -->
         <class>org.keycloak.events.jpa.EventEntity</class>
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.6.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.6.0.xml
new file mode 100644
index 0000000..24902d5
--- /dev/null
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.6.0.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+    <changeSet author="mposolda@redhat.com" id="1.6.0">
+
+        <addColumn tableName="KEYCLOAK_ROLE">
+            <column name="SCOPE_PARAM_REQUIRED" type="BOOLEAN" defaultValueBoolean="false">
+                <constraints nullable="false"/>
+            </column>
+        </addColumn>
+
+        <createTable tableName="OFFLINE_USER_SESSION">
+            <column name="USER_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="USER_SESSION_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="DATA" type="CLOB"/>
+        </createTable>
+
+        <createTable tableName="OFFLINE_CLIENT_SESSION">
+            <column name="USER_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="CLIENT_SESSION_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="USER_SESSION_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="CLIENT_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="DATA" type="CLOB"/>
+        </createTable>
+
+        <addPrimaryKey columnNames="USER_SESSION_ID" constraintName="CONSTRAINT_OFFLINE_US_SES_PK" tableName="OFFLINE_USER_SESSION"/>
+        <addPrimaryKey columnNames="CLIENT_SESSION_ID" constraintName="CONSTRAINT_OFFLINE_CL_SES_PK" tableName="OFFLINE_CLIENT_SESSION"/>
+        <addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="OFFLINE_USER_SESSION" constraintName="FK_OFFLINE_US_SES_USER" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
+        <addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="OFFLINE_CLIENT_SESSION" constraintName="FK_OFFLINE_CL_SES_USER" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
+        <addForeignKeyConstraint baseColumnNames="USER_SESSION_ID" baseTableName="OFFLINE_CLIENT_SESSION" constraintName="FK_OFFLINE_CL_US_SES" referencedColumnNames="USER_SESSION_ID" referencedTableName="OFFLINE_USER_SESSION"/>
+
+    </changeSet>
+</databaseChangeLog>
\ No newline at end of file
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml
index ca5d0e9..6cd96c6 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml
@@ -9,4 +9,5 @@
     <include file="META-INF/jpa-changelog-1.3.0.xml"/>
     <include file="META-INF/jpa-changelog-1.4.0.xml"/>
     <include file="META-INF/jpa-changelog-1.5.0.xml"/>
+    <include file="META-INF/jpa-changelog-1.6.0.xml"/>
 </databaseChangeLog>
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
index 423bf3e..90e8c98 100755
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
@@ -48,6 +48,8 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
             "org.keycloak.models.entities.AuthenticationFlowEntity",
             "org.keycloak.models.entities.AuthenticatorConfigEntity",
             "org.keycloak.models.entities.RequiredActionProviderEntity",
+            "org.keycloak.models.entities.OfflineUserSessionEntity",
+            "org.keycloak.models.entities.OfflineClientSessionEntity",
     };
 
     private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);

core/pom.xml 5(+0 -5)

diff --git a/core/pom.xml b/core/pom.xml
index e470755..7ea016a 100755
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -29,27 +29,22 @@
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk15on</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcpkix-jdk15on</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>net.iharder</groupId>
             <artifactId>base64</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-core-asl</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-mapper-asl</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java
index e17d21f..022dadd 100644
--- a/core/src/main/java/org/keycloak/OAuth2Constants.java
+++ b/core/src/main/java/org/keycloak/OAuth2Constants.java
@@ -38,6 +38,9 @@ public interface OAuth2Constants {
     // https://tools.ietf.org/html/draft-jones-oauth-jwt-bearer-03#section-2.2
     String CLIENT_ASSERTION_TYPE_JWT = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
 
+    // http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
+    String OFFLINE_ACCESS = "offline_access";
+
 }
 
 
diff --git a/core/src/main/java/org/keycloak/representations/idm/AuthenticationExecutionRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/AuthenticationExecutionRepresentation.java
index 643170f..0ccdd07 100755
--- a/core/src/main/java/org/keycloak/representations/idm/AuthenticationExecutionRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/AuthenticationExecutionRepresentation.java
@@ -8,7 +8,6 @@ import java.util.Comparator;
 * @version $Revision: 1 $
 */
 public class AuthenticationExecutionRepresentation implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String authenticatorConfig;
     private String authenticator;
diff --git a/core/src/main/java/org/keycloak/representations/idm/AuthenticationFlowRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/AuthenticationFlowRepresentation.java
index f8ba6a8..d91e1e6 100755
--- a/core/src/main/java/org/keycloak/representations/idm/AuthenticationFlowRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/AuthenticationFlowRepresentation.java
@@ -8,7 +8,6 @@ import java.util.List;
  * @version $Revision: 1 $
  */
 public class AuthenticationFlowRepresentation implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String alias;
     private String description;
diff --git a/core/src/main/java/org/keycloak/representations/idm/AuthenticatorConfigRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/AuthenticatorConfigRepresentation.java
index 1f0b3ad..9bd5ad1 100755
--- a/core/src/main/java/org/keycloak/representations/idm/AuthenticatorConfigRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/AuthenticatorConfigRepresentation.java
@@ -9,7 +9,6 @@ import java.util.Map;
 * @version $Revision: 1 $
 */
 public class AuthenticatorConfigRepresentation implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String alias;
     private Map<String, String> config = new HashMap<String, String>();
diff --git a/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
index c335ab4..4100785 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
@@ -12,6 +12,7 @@ public class RoleRepresentation {
     protected String id;
     protected String name;
     protected String description;
+    protected Boolean scopeParamRequired;
     protected boolean composite;
     protected Composites composites;
 
@@ -46,9 +47,10 @@ public class RoleRepresentation {
     public RoleRepresentation() {
     }
 
-    public RoleRepresentation(String name, String description) {
+    public RoleRepresentation(String name, String description, boolean scopeParamRequired) {
         this.name = name;
         this.description = description;
+        this.scopeParamRequired = scopeParamRequired;
     }
 
     public String getId() {
@@ -75,6 +77,14 @@ public class RoleRepresentation {
         this.description = description;
     }
 
+    public Boolean isScopeParamRequired() {
+        return scopeParamRequired;
+    }
+
+    public void setScopeParamRequired(Boolean scopeParamRequired) {
+        this.scopeParamRequired = scopeParamRequired;
+    }
+
     public Composites getComposites() {
         return composites;
     }
diff --git a/core/src/main/java/org/keycloak/representations/RefreshToken.java b/core/src/main/java/org/keycloak/representations/RefreshToken.java
index 7bc1edf..ff1ce68 100755
--- a/core/src/main/java/org/keycloak/representations/RefreshToken.java
+++ b/core/src/main/java/org/keycloak/representations/RefreshToken.java
@@ -1,6 +1,7 @@
 package org.keycloak.representations;
 
 import org.codehaus.jackson.annotate.JsonProperty;
+import org.keycloak.util.RefreshTokenUtil;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -11,9 +12,8 @@ import java.util.Map;
  */
 public class RefreshToken extends AccessToken {
 
-
     private RefreshToken() {
-        type("REFRESH");
+        type(RefreshTokenUtil.TOKEN_TYPE_REFRESH);
     }
 
     /**
diff --git a/core/src/main/java/org/keycloak/util/RefreshTokenUtil.java b/core/src/main/java/org/keycloak/util/RefreshTokenUtil.java
new file mode 100644
index 0000000..0a759a5
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/RefreshTokenUtil.java
@@ -0,0 +1,62 @@
+package org.keycloak.util;
+
+import java.io.IOException;
+
+import org.keycloak.OAuth2Constants;
+import org.keycloak.representations.RefreshToken;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class RefreshTokenUtil {
+
+    public static final String TOKEN_TYPE_REFRESH = "REFRESH";
+
+    public static final String TOKEN_TYPE_OFFLINE = "OFFLINE";
+
+    public static boolean isOfflineTokenRequested(String scopeParam) {
+        if (scopeParam == null) {
+            return false;
+        }
+
+        String[] scopes = scopeParam.split(" ");
+        for (String scope : scopes) {
+            if (OAuth2Constants.OFFLINE_ACCESS.equals(scope)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Return refresh token or offline otkne
+     *
+     * @param decodedToken
+     * @return
+     */
+    public static RefreshToken getRefreshToken(byte[] decodedToken) throws IOException {
+        return JsonSerialization.readValue(decodedToken, RefreshToken.class);
+    }
+
+    private static RefreshToken getRefreshToken(String refreshToken) throws IOException {
+        byte[] decodedToken = Base64Url.decode(refreshToken);
+        return getRefreshToken(decodedToken);
+    }
+
+    /**
+     * Return true if given refreshToken represents offline token
+     *
+     * @param refreshToken
+     * @return
+     */
+    public static boolean isOfflineToken(String refreshToken) {
+        try {
+            RefreshToken token = getRefreshToken(refreshToken);
+            return token.getType().equals(TOKEN_TYPE_OFFLINE);
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+}
diff --git a/distribution/docs-dist/pom.xml b/distribution/docs-dist/pom.xml
index 1f1ce1d..fdee7b4 100755
--- a/distribution/docs-dist/pom.xml
+++ b/distribution/docs-dist/pom.xml
@@ -14,12 +14,40 @@
     <description/>
 
     <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-dependencies-server-all</artifactId>
+            <type>pom</type>
+        </dependency>
     </dependencies>
+
     <build>
         <finalName>keycloak-docs-${project.version}</finalName>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <minmemory>128m</minmemory>
+                    <maxmemory>1024m</maxmemory>
+                    <dependencySourceIncludes>
+                        <dependencySourceInclude>org.keycloak:*</dependencySourceInclude>
+                    </dependencySourceIncludes>
+                    <includeDependencySources>true</includeDependencySources>
+                    <includeTransitiveDependencySources>true</includeTransitiveDependencySources>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>aggregate-javadoc</id>
+                        <phase>compile</phase>
+                        <goals>
+                            <goal>javadoc</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-deploy-plugin</artifactId>
                 <configuration>
                     <skip>true</skip>
diff --git a/docbook/reference/en/en-US/modules/auth-spi.xml b/docbook/reference/en/en-US/modules/auth-spi.xml
index ff7f061..10cb89d 100755
--- a/docbook/reference/en/en-US/modules/auth-spi.xml
+++ b/docbook/reference/en/en-US/modules/auth-spi.xml
@@ -898,7 +898,7 @@ public class SecretQuestionRequiredActionFactory implements RequiredActionFactor
 }
 ]]></programlisting>
 
-                                where the <literal>mysecret</literal> needs to be replaced with the real value of client secret. You can obtain it from client admin console.
+                                where the <literal>mysecret</literal> needs to be replaced with the real value of client secret. You can obtain it from admin console from client configuration.
                             </para>
                         </listitem>
                     </varlistentry>
@@ -906,7 +906,7 @@ public class SecretQuestionRequiredActionFactory implements RequiredActionFactor
                         <term>Authentication with signed JWT</term>
                         <listitem>
                             <para>
-                                This is based on the <ulink url="https://tools.ietf.org/html/draft-jones-oauth-jwt-bearer-03">JWT Bearer Token Profiles for OAuth 2.0</ulink> specification.
+                                This is based on the <ulink url="https://tools.ietf.org/html/rfc7523">JWT Bearer Token Profiles for OAuth 2.0</ulink> specification.
                                 The client/adapter generates the <ulink url="https://tools.ietf.org/html/rfc7519">JWT</ulink> and signs it with his private key.
                                 The Keycloak then verifies the signed JWT with the client's public key and authenticates client based on it.
                             </para>
diff --git a/events/api/src/main/java/org/keycloak/events/Details.java b/events/api/src/main/java/org/keycloak/events/Details.java
index b7ec677..b9c5338 100755
--- a/events/api/src/main/java/org/keycloak/events/Details.java
+++ b/events/api/src/main/java/org/keycloak/events/Details.java
@@ -20,6 +20,7 @@ public interface Details {
     String REMEMBER_ME = "remember_me";
     String TOKEN_ID = "token_id";
     String REFRESH_TOKEN_ID = "refresh_token_id";
+    String REFRESH_TOKEN_TYPE = "refresh_token_type";
     String VALIDATE_ACCESS_TOKEN = "validate_access_token";
     String UPDATED_REFRESH_TOKEN_ID = "updated_refresh_token_id";
     String NODE_HOST = "node_host";
diff --git a/events/jpa/pom.xml b/events/jpa/pom.xml
index d6e7e9e..9fbd1d8 100755
--- a/events/jpa/pom.xml
+++ b/events/jpa/pom.xml
@@ -35,7 +35,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/UnknownProductFault.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/UnknownProductFault.java
index 671b71e..d9aa035 100644
--- a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/UnknownProductFault.java
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/UnknownProductFault.java
@@ -4,7 +4,6 @@ import javax.xml.ws.WebFault;
 
 @WebFault(name = "UnknownProductFault")
 public class UnknownProductFault extends Exception {
-    public static final long serialVersionUID = 20081110144906L;
 
     private org.keycloak.example.ws.types.UnknownProductFault unknownProductFault;
 
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/ApplicationsBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/ApplicationsBean.java
index 9d9035a..371b5d0 100644
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/ApplicationsBean.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/ApplicationsBean.java
@@ -1,5 +1,6 @@
 package org.keycloak.account.freemarker.model;
 
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
@@ -11,6 +12,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.services.offline.OfflineTokenUtils;
 import org.keycloak.util.MultivaluedHashMap;
 
 /**
@@ -21,6 +23,9 @@ public class ApplicationsBean {
     private List<ApplicationEntry> applications = new LinkedList<ApplicationEntry>();
 
     public ApplicationsBean(RealmModel realm, UserModel user) {
+
+        Set<ClientModel> offlineClients = OfflineTokenUtils.findClientsWithOfflineToken(realm, user);
+
         List<ClientModel> realmClients = realm.getClients();
         for (ClientModel client : realmClients) {
             // Don't show bearerOnly clients
@@ -28,7 +33,7 @@ public class ApplicationsBean {
                 continue;
             }
 
-            Set<RoleModel> availableRoles = TokenManager.getAccess(null, client, user);
+            Set<RoleModel> availableRoles = TokenManager.getAccess(null, false, client, user);
             // Don't show applications, which user doesn't have access into (any available roles)
             if (availableRoles.isEmpty()) {
                 continue;
@@ -52,7 +57,13 @@ public class ApplicationsBean {
                 }
             }
 
-            ApplicationEntry appEntry = new ApplicationEntry(realmRolesAvailable, resourceRolesAvailable, realmRolesGranted, resourceRolesGranted, client, claimsGranted);
+            List<String> additionalGrants = new ArrayList<>();
+            if (offlineClients.contains(client)) {
+                additionalGrants.add("${offlineToken}");
+            }
+
+            ApplicationEntry appEntry = new ApplicationEntry(realmRolesAvailable, resourceRolesAvailable, realmRolesGranted, resourceRolesGranted, client,
+                    claimsGranted, additionalGrants);
             applications.add(appEntry);
         }
     }
@@ -82,16 +93,18 @@ public class ApplicationsBean {
         private final MultivaluedHashMap<String, ClientRoleEntry> resourceRolesGranted;
         private final ClientModel client;
         private final List<String> claimsGranted;
+        private final List<String> additionalGrants;
 
         public ApplicationEntry(List<RoleModel> realmRolesAvailable, MultivaluedHashMap<String, ClientRoleEntry> resourceRolesAvailable,
                                 List<RoleModel> realmRolesGranted, MultivaluedHashMap<String, ClientRoleEntry> resourceRolesGranted,
-                                ClientModel client, List<String> claimsGranted) {
+                                ClientModel client, List<String> claimsGranted, List<String> additionalGrants) {
             this.realmRolesAvailable = realmRolesAvailable;
             this.resourceRolesAvailable = resourceRolesAvailable;
             this.realmRolesGranted = realmRolesGranted;
             this.resourceRolesGranted = resourceRolesGranted;
             this.client = client;
             this.claimsGranted = claimsGranted;
+            this.additionalGrants = additionalGrants;
         }
 
         public List<RoleModel> getRealmRolesAvailable() {
@@ -118,6 +131,9 @@ public class ApplicationsBean {
             return claimsGranted;
         }
 
+        public List<String> getAdditionalGrants() {
+            return additionalGrants;
+        }
     }
 
     // Same class used in OAuthGrantBean as well. Maybe should be merged into common-freemarker...
diff --git a/forms/common-themes/src/main/resources/theme/base/account/applications.ftl b/forms/common-themes/src/main/resources/theme/base/account/applications.ftl
index 4e01c02..b2bbdf2 100755
--- a/forms/common-themes/src/main/resources/theme/base/account/applications.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/account/applications.ftl
@@ -18,6 +18,7 @@
                 <td>${msg("availablePermissions")}</td>
                 <td>${msg("grantedPermissions")}</td>
                 <td>${msg("grantedPersonalInfo")}</td>
+                <td>${msg("additionalGrants")}</td>
                 <td>${msg("action")}</td>
               </tr>
             </thead>
@@ -76,7 +77,13 @@
                     </td>
 
                     <td>
-                        <#if application.client.consentRequired && application.claimsGranted?has_content>
+                       <#list application.additionalGrants as grant>
+                            ${advancedMsg(grant)}<#if grant_has_next>, </#if>
+                        </#list>
+                    </td>
+
+                    <td>
+                        <#if (application.client.consentRequired && application.claimsGranted?has_content) || application.additionalGrants?has_content>
                             <button type='submit' class='${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!}' id='revoke-${application.client.clientId}' name='clientId' value="${application.client.id}">${msg("revoke")}</button>
                         </#if>
                     </td>
diff --git a/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
index 2c3b8c7..23a112d 100755
--- a/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
@@ -52,6 +52,7 @@ role_manage-events=Manage events
 role_view-profile=View profile
 role_manage-account=Manage account
 role_read-token=Read token
+role_offline-access=Offline access
 client_account=Account
 client_security-admin-console=Security Admin Console
 client_realm-management=Realm Management
@@ -85,9 +86,11 @@ application=Application
 availablePermissions=Available Permissions
 grantedPermissions=Granted Permissions
 grantedPersonalInfo=Granted Personal Info
+additionalGrants=Additional Grants
 action=Action
 inResource=in
 fullAccess=Full Access
+offlineToken=Offline Token
 revoke=Revoke Grant
 
 configureAuthenticators=Configured Authenticators
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
index 903131d..756c89e 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -2036,3 +2036,26 @@ module.directive( 'kcOpen', function ( $location ) {
         });
     };
 });
+
+module.directive('kcOnReadFile', function ($parse) {
+    console.debug('kcOnReadFile');
+    return {
+        restrict: 'A',
+        scope: false,
+        link: function(scope, element, attrs) {
+            var fn = $parse(attrs.kcOnReadFile);
+
+            element.on('change', function(onChangeEvent) {
+                var reader = new FileReader();
+
+                reader.onload = function(onLoadEvent) {
+                    scope.$apply(function() {
+                        fn(scope, {$fileContent:onLoadEvent.target.result});
+                    });
+                };
+
+                reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0]);
+            });
+        }
+    };
+});
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index 4027a85..15dc679 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -155,7 +155,7 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
     }
 });
 
-module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, WhoAmI, $location, Dialog, Notifications, Auth) {
+module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, WhoAmI, $location, $route, Dialog, Notifications, Auth, $modal) {
     console.log('RealmCreateCtrl');
 
     Current.realm = null;
@@ -169,55 +169,21 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
 
     var oldCopy = angular.copy($scope.realm);
 
-    $scope.onFileSelect = function($files) {
-        $scope.files = $files;
+    $scope.importFile = function($fileContent){
+        $scope.realm = angular.copy(JSON.parse($fileContent));
+        $scope.importing = true;
     };
 
-    $scope.clearFileSelect = function() {
-        $scope.files = null;
-    }
-
-    $scope.uploadFile = function() {
-        //$files: an array of files selected, each file has name, size, and type.
-        for (var i = 0; i < $scope.files.length; i++) {
-            var $file = $scope.files[i];
-            $scope.upload = $upload.upload({
-                url: authUrl + '/admin/realms', //upload.php script, node.js route, or servlet url
-                // method: POST or PUT,
-                // headers: {'headerKey': 'headerValue'}, withCredential: true,
-                data: {myObj: ""},
-                file: $file
-                /* set file formData name for 'Content-Desposition' header. Default: 'file' */
-                //fileFormDataName: myFile,
-                /* customize how data is added to formData. See #40#issuecomment-28612000 for example */
-                //formDataAppender: function(formData, key, val){}
-            }).progress(function(evt) {
-                    console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
-                }).success(function(data, status, headers) {
-                    Realm.query(function(data) {
-                        Current.realms = data;
-
-
-                        WhoAmI.get(function(user) {
-                            Auth.user = user;
-
-                            Notifications.success("The realm has been uploaded.");
-
-                            var location = headers('Location');
-                            if (location) {
-                                $location.url("/realms/" + location.substring(location.lastIndexOf('/') + 1));
-                            } else {
-                                $location.url("/realms");
-                            }
-                        });
-                    });
-                })
-            .error(function() {
-                    Notifications.error("The realm can not be uploaded. Please verify the file.");
-
-                });
-            //.then(success, error, progress);
-        }
+    $scope.viewImportDetails = function() {
+        $modal.open({
+            templateUrl: resourceUrl + '/partials/modal/view-object.html',
+            controller: 'ObjectModalCtrl',
+            resolve: {
+                object: function () {
+                    return $scope.realm;
+                }
+            }
+        })
     };
 
     $scope.$watch('realm', function() {
@@ -226,6 +192,12 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
         }
     }, true);
 
+    $scope.$watch('realm.realm', function() {
+	if (create) {
+	    $scope.realm.id = $scope.realm.realm;
+	}
+    }, true);
+
     $scope.save = function() {
         var realmCopy = angular.copy($scope.realm);
         Realm.create(realmCopy, function() {
@@ -243,10 +215,17 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
     };
 
     $scope.cancel = function() {
-        window.history.back();
+        $location.url("/");
     };
+
+    $scope.reset = function() {
+        $route.reload();
+    }
 });
 
+module.controller('ObjectModalCtrl', function($scope, object) {
+    $scope.object = object;
+});
 
 module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $location, Dialog, Notifications, WhoAmI, Auth) {
     $scope.createRealm = !realm.realm;
@@ -693,10 +672,17 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
 
             }
         ];
+        $scope.signatureAlgorithms = [
+            "RSA_SHA1",
+            "RSA_SHA256",
+            "RSA_SHA512",
+            "DSA_SHA1"
+        ];
         if (instance && instance.alias) {
 
         } else {
             $scope.identityProvider.config.nameIDPolicyFormat = $scope.nameIdFormats[0].format;
+            $scope.identityProvider.config.signatureAlgorithm = $scope.signatureAlgorithms[1];
             $scope.identityProvider.updateProfileFirstLoginMode = "off";
         }
     }
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-role-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-role-detail.html
index c0ce766..f93c96e 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-role-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-role-detail.html
@@ -32,6 +32,13 @@
                                                            required> -->
                 </div>
             </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="scopeParamRequired">Scope Param Required </label>
+                <kc-tooltip>This role will be granted just if scope parameter with role name is used during authorization/token request.</kc-tooltip>
+                <div class="col-md-6">
+                    <input ng-model="role.scopeParamRequired" name="scopeParamRequired" id="scopeParamRequired" onoffswitch />
+                </div>
+            </div>
             <div class="form-group clearfix block" data-ng-hide="create">
                 <label class="col-md-2 control-label" for="compositeSwitch" class="control-label">Composite Roles</label>
                 <div class="col-md-6">
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/view-object.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/view-object.html
new file mode 100644
index 0000000..ee50aee
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/view-object.html
@@ -0,0 +1,3 @@
+<div style="padding: 20px 20px 10px 20px">
+	<pre ng-bind = "{{object}} | json"></pre>
+</div>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/password-policy.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/password-policy.html
index 2da9b0d..58942ce 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/password-policy.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/password-policy.html
@@ -34,7 +34,7 @@
                            placeholder="No value assigned" min="1" required>
                 </td>
                 <td class="kc-action-cell">
-                    <button class="btn btn-default btn-block btn-sm" ng-click="removePolicy($index)">Delete</button>
+                    <button type="button" class="btn btn-default btn-block btn-sm" ng-click="removePolicy($index)">Delete</button>
                 </td>
             </tr>
             </tbody>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-create.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-create.html
index 630188d..4ac36fd 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-create.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-create.html
@@ -1,29 +1,22 @@
 <div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
     <form class="form-horizontal" name="realmForm" novalidate>
         <fieldset>
-            <legend><span class="text">Import Realm</span></legend>
+            <legend><span class="text">Create Realm</span></legend>
             <div class="form-group">
-                <label for="import-file" class="col-sm-2 control-label">Import JSON File </label>
-                <div class="col-md-6">
-                    <div class="controls kc-button-input-file" data-ng-show="!files || files.length == 0">
-                        <label for="import-file" class="btn btn-default">Select file <i class="pficon pficon-import"></i></label>
-                        <input id="import-file" type="file" class="hidden" ng-file-select="onFileSelect($files)">
-                    </div>
-                    <span class="kc-uploaded-file" data-ng-show="files.length > 0">{{files[0].name}}</span>
+                <label for="name" class="col-sm-2 control-label">Import</label>
+
+                <div class="col-md-6" data-ng-hide="importing">
+                    <label for="import-file" class="btn btn-default">Select file <i class="pficon pficon-import"></i></label>
+                    <input id="import-file" type="file" class="hidden" kc-on-read-file="importFile($fileContent)">
                 </div>
-            </div>
-            <div class="form-group">
-                <div class="col-md-10 col-md-offset-2">
-                    <button type="submit" data-ng-disabled="files.length == 0" data-ng-click="uploadFile()" class="btn btn-primary">Upload</button>
-                    <button type="submit" data-ng-disabled="files.length == 0" data-ng-click="clearFileSelect()" class="btn btn-default">Cancel</button>
+
+                <div class="col-md-6" data-ng-show="importing">
+                    <button class="btn btn-default" data-ng-click="viewImportDetails()">View details</button>
+                    <button class="btn btn-default" data-ng-click="reset()">Clear import</button>
                 </div>
             </div>
-        </fieldset>
-    </form>
 
-    <form class="form-horizontal" name="realmForm" novalidate>
-        <fieldset>
-            <legend><span class="text">Create Realm</span></legend>
             <div class="form-group">
                 <label for="name" class="col-sm-2 control-label">Name <span class="required">*</span></label>
 
@@ -42,6 +35,7 @@
         <div class="form-group">
             <div class="col-md-10 col-md-offset-2">
                 <button kc-save data-ng-disabled="!changed">Create</button>
+                <button kc-cancel data-ng-click="cancel()">Cancel</button>
             </div>
         </div>
     </form>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
index 1723919..5387826 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
@@ -135,6 +135,18 @@
                 </div>
                 <kc-tooltip> Indicates whether the identity provider expects signed a AuthnRequest.</kc-tooltip>
             </div>
+            <div class="form-group" data-ng-show="identityProvider.config.wantAuthnRequestsSigned == 'true'">
+                <label class="col-md-2 control-label" for="signatureAlgorithm">Signature Algorithm</label>
+                <div class="col-sm-6">
+                    <div>
+                        <select class="form-control" id="signatureAlgorithm"
+                                ng-model="identityProvider.config.signatureAlgorithm"
+                                ng-options="alg for alg in signatureAlgorithms">
+                        </select>
+                    </div>
+                </div>
+                <kc-tooltip>The signature algorithm to use to sign documents.</kc-tooltip>
+            </div>
             <div class="form-group">
                 <label class="col-md-2 control-label" for="forceAuthn">Force Authentication</label>
                 <div class="col-md-6">
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
index 49d09c8..6bf854e 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
@@ -28,6 +28,13 @@
                     <textarea class="form-control" rows="5" cols="50" id="description" name="description" data-ng-model="role.description"></textarea>
                 </div>
             </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="scopeParamRequired">Scope Param Required </label>
+                <kc-tooltip>This role will be granted just if scope parameter with role name is used during authorization/token request.</kc-tooltip>
+                <div class="col-md-6">
+                    <input ng-model="role.scopeParamRequired" name="scopeParamRequired" id="scopeParamRequired" onoffswitch />
+                </div>
+            </div>
             <div class="form-group" data-ng-hide="create">
                 <label class="col-md-2 control-label" for="compositeSwitch" class="control-label">Composite Roles</label>
                 <div class="col-md-6">
diff --git a/forms/common-themes/src/main/resources/theme/base/login/login-update-profile.ftl b/forms/common-themes/src/main/resources/theme/base/login/login-update-profile.ftl
index 2257508..584bea3 100755
--- a/forms/common-themes/src/main/resources/theme/base/login/login-update-profile.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/login/login-update-profile.ftl
@@ -6,6 +6,16 @@
         ${msg("loginProfileTitle")}
     <#elseif section = "form">
         <form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
+            <#if realm.editUsernameAllowed>
+                <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('username',properties.kcFormGroupErrorClass!)}">
+                    <div class="${properties.kcLabelWrapperClass!}">
+                        <label for="username" class="${properties.kcLabelClass!}">${msg("username")}</label>
+                    </div>
+                    <div class="${properties.kcInputWrapperClass!}">
+                        <input type="text" id="username" name="username" value="${(user.username!'')?html}" class="${properties.kcInputClass!}"/>
+                    </div>
+                </div>
+            </#if>
             <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('email',properties.kcFormGroupErrorClass!)}">
                 <div class="${properties.kcLabelWrapperClass!}">
                     <label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
diff --git a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
index 3dfb8ea..94b0627 100644
--- a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
@@ -104,6 +104,7 @@ role_manage-events=Manage events
 role_view-profile=View profile
 role_manage-account=Manage account
 role_read-token=Read token
+role_offline-access=Offline access
 client_account=Account
 client_security-admin-console=Security Admin Console
 client_realm-management=Realm Management
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/ProfileBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/ProfileBean.java
index 6f73cc5..e730c14 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/ProfileBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/ProfileBean.java
@@ -70,6 +70,8 @@ public class ProfileBean {
 
     }
 
+    public String getUsername() { return formData != null ? formData.getFirst("username") : user.getUsername(); }
+
     public String getFirstName() {
         return formData != null ? formData.getFirst("firstName") : user.getFirstName();
     }
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
index b161ad2..e6ae21d 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
@@ -66,6 +66,10 @@ public class RealmBean {
         return realm.isInternationalizationEnabled();
     }
 
+    public boolean isEditUsernameAllowed() {
+        return realm.isEditUsernameAllowed();
+    }
+
     public boolean isPassword() {
         for (RequiredCredentialModel r : realm.getRequiredCredentials()) {
             if (r.getType().equals(CredentialRepresentation.PASSWORD)) {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/authentication/ClientCredentialsProvider.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/authentication/ClientCredentialsProvider.java
index 80a0c4d..2c6a92d 100644
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/authentication/ClientCredentialsProvider.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/authentication/ClientCredentialsProvider.java
@@ -14,7 +14,7 @@ import org.keycloak.adapters.KeycloakDeployment;
  *
  * You must specify a file
  * META-INF/services/org.keycloak.adapters.authentication.ClientCredentialsProvider in the WAR that this class is contained in (or in the JAR that is attached to the WEB-INF/lib or as jboss module
- * if you want to share the implementation among more WARs). This file must have the fully qualified class name of all your ClientAuthenticatorFactory classes
+ * if you want to share the implementation among more WARs).
  *
  * NOTE: The SPI is not finished and method signatures are still subject to change in future versions (for example to support
  * authentication with client certificate)
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/authentication/JWTClientCredentialsProvider.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/authentication/JWTClientCredentialsProvider.java
index d68c7cb..1c8907e 100644
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/authentication/JWTClientCredentialsProvider.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/authentication/JWTClientCredentialsProvider.java
@@ -13,7 +13,7 @@ import org.keycloak.util.Time;
 
 /**
  * Client authentication based on JWT signed by client private key .
- * See <a href="https://tools.ietf.org/html/draft-jones-oauth-jwt-bearer-03">specs</a> for more details.
+ * See <a href="https://tools.ietf.org/html/rfc7519">specs</a> for more details.
  *
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/RolePrincipal.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/RolePrincipal.java
index a4e4423..d578c81 100644
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/RolePrincipal.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/RolePrincipal.java
@@ -8,7 +8,6 @@ import java.security.Principal;
  */
 public class RolePrincipal implements Principal, Serializable {
 
-    private static final long serialVersionUID = -5538962177019315447L;
     private String roleName = null;
 
     public RolePrincipal(String roleName) {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
index 1dfe41d..d077d7d 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
@@ -134,6 +134,9 @@ public class OAuthRequestAuthenticator {
         String idpHint = getQueryParamValue(AdapterConstants.KC_IDP_HINT);
         url = UriUtils.stripQueryParam(url, AdapterConstants.KC_IDP_HINT);
 
+        String scope = getQueryParamValue(OAuth2Constants.SCOPE);
+        url = UriUtils.stripQueryParam(url, OAuth2Constants.SCOPE);
+
         KeycloakUriBuilder redirectUriBuilder = deployment.getAuthUrl().clone()
                 .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
                 .queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
@@ -146,6 +149,9 @@ public class OAuthRequestAuthenticator {
         if (idpHint != null && idpHint.length() > 0) {
             redirectUriBuilder.queryParam(AdapterConstants.KC_IDP_HINT,idpHint);
         }
+        if (scope != null && scope.length() > 0) {
+            redirectUriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
+        }
 
         return redirectUriBuilder.build().toString();
     }
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
index 52668de..b938a0b 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
@@ -117,7 +117,12 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
         }
 
         this.token = token;
-        this.refreshToken = response.getRefreshToken();
+        if (response.getRefreshToken() != null) {
+            if (log.isTraceEnabled()) {
+                log.trace("Setup new refresh token to the security context");
+            }
+            this.refreshToken = response.getRefreshToken();
+        }
         this.tokenString = tokenString;
         tokenStore.refreshCallback(this);
         return true;
diff --git a/integration/js/src/main/resources/keycloak.js b/integration/js/src/main/resources/keycloak.js
index 46d3b18..f384e7b 100755
--- a/integration/js/src/main/resources/keycloak.js
+++ b/integration/js/src/main/resources/keycloak.js
@@ -164,6 +164,10 @@
                 url += '&kc_idp_hint=' + options.idpHint;
             }
 
+            if (options && options.scope) {
+                url += '&scope=' + options.scope;
+            }
+
             return url;
         }
 
diff --git a/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/SimpleGroup.java b/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/SimpleGroup.java
index 53bb52c..109ffe1 100755
--- a/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/SimpleGroup.java
+++ b/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/SimpleGroup.java
@@ -8,7 +8,6 @@ import java.util.HashSet;
 import java.util.Set;
 
 public class SimpleGroup extends SimplePrincipal implements Group {
-    private static final long serialVersionUID = 3273437693505893786L;
     private final Set<Principal> members = new HashSet<Principal>();
 
     /**
diff --git a/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/SimplePrincipal.java b/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/SimplePrincipal.java
index ada37d7..29f46ec 100755
--- a/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/SimplePrincipal.java
+++ b/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/SimplePrincipal.java
@@ -14,7 +14,6 @@ import java.security.Principal;
 public class SimplePrincipal implements Principal, Serializable {
 
     /** SimplePrincipal.java */
-    private static final long serialVersionUID = -5645357206342793145L;
 
     /** The unique identifier for this principal. */
     private final String name;
diff --git a/misc/ReleaseProcess.md b/misc/ReleaseProcess.md
index 9a0e3d4..1fa620b 100644
--- a/misc/ReleaseProcess.md
+++ b/misc/ReleaseProcess.md
@@ -7,31 +7,21 @@
 
 ## Release
 
-*Releasing currently requires using JDK 7 due to a bug in JAX-RS Doclets*
-
 ### Clone from GitHub
 
     # git clone https://github.com/keycloak/keycloak.git
     # cd keycloak
 
-### Update version
-
-    # mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false -Pjboss-release
+### Prepare the release
 
-### Build
+    # mvn -Pjboss-release release:prepare
 
-    # mvn install install -Pdistribution
-    # mvn install -Pjboss-release -DskipTests
+### Perform the release
 
-### Tag
-
-    # git tag $VERSION
-    # git push --tags
+    # mvn -Pjboss-release release:perform
 
 ### Deploy to Nexus
 
-    # mvn deploy -DskipTests -Pjboss-release
-
 Then login to Nexus and release the maven uploads in the staging area. Artifacts will eventually be synced to Maven Central, but this can take up to 24 hours.
 
 ### Upload
@@ -51,7 +41,6 @@ Upload all artifacts to downloads.jboss.org (see https://mojo.redhat.com/docs/DO
     # git tag $VERSION
     # git push --tags
 
-
 ## After Release
 
 ### Update Bower
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationModel.java b/model/api/src/main/java/org/keycloak/migration/MigrationModel.java
index 792822e..beb2f98 100755
--- a/model/api/src/main/java/org/keycloak/migration/MigrationModel.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationModel.java
@@ -11,7 +11,7 @@ public interface MigrationModel {
     /**
      * Must have the form of major.minor.micro as the version is parsed and numbers are compared
      */
-    public static final String LATEST_VERSION = "1.5.0";
+    public static final String LATEST_VERSION = "1.6.0";
 
     String getStoredVersion();
     void setStoredVersion(String version);
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
index 61b6244..e5c9484 100755
--- a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
@@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
 import org.keycloak.migration.migrators.MigrateTo1_3_0;
 import org.keycloak.migration.migrators.MigrateTo1_4_0;
 import org.keycloak.migration.migrators.MigrateTo1_5_0;
+import org.keycloak.migration.migrators.MigrateTo1_6_0;
 import org.keycloak.migration.migrators.MigrationTo1_2_0_CR1;
 import org.keycloak.models.KeycloakSession;
 
@@ -47,6 +48,12 @@ public class MigrationModelManager {
             }
             new MigrateTo1_5_0().migrate(session);
         }
+        if (stored == null || stored.lessThan(MigrateTo1_6_0.VERSION)) {
+            if (stored != null) {
+                logger.debug("Migrating older model to 1.6.0 updates");
+            }
+            new MigrateTo1_6_0().migrate(session);
+        }
 
         model.setStoredVersion(MigrationModel.LATEST_VERSION);
     }
diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java
new file mode 100644
index 0000000..8010586
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java
@@ -0,0 +1,25 @@
+package org.keycloak.migration.migrators;
+
+import java.util.List;
+
+import org.keycloak.migration.ModelVersion;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class MigrateTo1_6_0 {
+
+    public static final ModelVersion VERSION = new ModelVersion("1.6.0");
+
+    public void migrate(KeycloakSession session) {
+        List<RealmModel> realms = session.realms().getRealms();
+        for (RealmModel realm : realms) {
+            KeycloakModelUtils.setupOfflineTokens(realm);
+        }
+
+    }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrationTo1_2_0_CR1.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrationTo1_2_0_CR1.java
index c9e10ad..1aa4929 100755
--- a/model/api/src/main/java/org/keycloak/migration/migrators/MigrationTo1_2_0_CR1.java
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrationTo1_2_0_CR1.java
@@ -5,6 +5,7 @@ import org.keycloak.models.ClientModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import java.util.List;
@@ -26,7 +27,9 @@ public class MigrationTo1_2_0_CR1 {
             client.setFullScopeAllowed(false);
 
             for (String role : Constants.BROKER_SERVICE_ROLES) {
-                client.addRole(role).setDescription("${role_"+ role.toLowerCase().replaceAll("_", "-") +"}");
+                RoleModel roleModel = client.addRole(role);
+                roleModel.setDescription("${role_" + role.toLowerCase().replaceAll("_", "-") + "}");
+                roleModel.setScopeParamRequired(false);
             }
         }
     }
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
index acb3975..04c24a9 100755
--- a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
@@ -8,7 +8,6 @@ import java.io.Serializable;
 * @version $Revision: 1 $
 */
 public class AuthenticationExecutionModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     public static class ExecutionComparator implements Comparator<AuthenticationExecutionModel> {
         public static final ExecutionComparator SINGLETON = new ExecutionComparator();
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java
index f538d30..1db5970 100755
--- a/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java
@@ -7,7 +7,6 @@ import java.io.Serializable;
  * @version $Revision: 1 $
  */
 public class AuthenticationFlowModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String id;
     private String alias;
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticatorConfigModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticatorConfigModel.java
index 9e7f46d..22e3cfa 100755
--- a/model/api/src/main/java/org/keycloak/models/AuthenticatorConfigModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticatorConfigModel.java
@@ -9,7 +9,6 @@ import java.util.Map;
 * @version $Revision: 1 $
 */
 public class AuthenticatorConfigModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String id;
     private String alias;
diff --git a/model/api/src/main/java/org/keycloak/models/Constants.java b/model/api/src/main/java/org/keycloak/models/Constants.java
index b1adbfa..5fe3189 100755
--- a/model/api/src/main/java/org/keycloak/models/Constants.java
+++ b/model/api/src/main/java/org/keycloak/models/Constants.java
@@ -1,5 +1,7 @@
 package org.keycloak.models;
 
+import org.keycloak.OAuth2Constants;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
@@ -16,4 +18,5 @@ public interface Constants {
     String INSTALLED_APP_URL = "http://localhost";
     String READ_TOKEN_ROLE = "read-token";
     String[] BROKER_SERVICE_ROLES = {READ_TOKEN_ROLE};
+    String OFFLINE_ACCESS_ROLE = OAuth2Constants.OFFLINE_ACCESS;
 }
diff --git a/model/api/src/main/java/org/keycloak/models/entities/OfflineClientSessionEntity.java b/model/api/src/main/java/org/keycloak/models/entities/OfflineClientSessionEntity.java
new file mode 100644
index 0000000..69ad60b
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/OfflineClientSessionEntity.java
@@ -0,0 +1,35 @@
+package org.keycloak.models.entities;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OfflineClientSessionEntity {
+
+    private String clientSessionId;
+    private String clientId;
+    private String data;
+
+    public String getClientSessionId() {
+        return clientSessionId;
+    }
+
+    public void setClientSessionId(String clientSessionId) {
+        this.clientSessionId = clientSessionId;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/OfflineUserSessionEntity.java b/model/api/src/main/java/org/keycloak/models/entities/OfflineUserSessionEntity.java
new file mode 100644
index 0000000..e785898
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/OfflineUserSessionEntity.java
@@ -0,0 +1,37 @@
+package org.keycloak.models.entities;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OfflineUserSessionEntity {
+
+    private String userSessionId;
+    private String data;
+    private List<OfflineClientSessionEntity> offlineClientSessions;
+
+    public String getUserSessionId() {
+        return userSessionId;
+    }
+
+    public void setUserSessionId(String userSessionId) {
+        this.userSessionId = userSessionId;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+
+    public List<OfflineClientSessionEntity> getOfflineClientSessions() {
+        return offlineClientSessions;
+    }
+
+    public void setOfflineClientSessions(List<OfflineClientSessionEntity> offlineClientSessions) {
+        this.offlineClientSessions = offlineClientSessions;
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RoleEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RoleEntity.java
index a610d39..4b4551e 100644
--- a/model/api/src/main/java/org/keycloak/models/entities/RoleEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/RoleEntity.java
@@ -9,6 +9,7 @@ public class RoleEntity extends AbstractIdentifiableEntity {
 
     private String name;
     private String description;
+    private boolean scopeParamRequired;
 
     private List<String> compositeRoleIds;
 
@@ -31,6 +32,14 @@ public class RoleEntity extends AbstractIdentifiableEntity {
         this.description = description;
     }
 
+    public boolean isScopeParamRequired() {
+        return scopeParamRequired;
+    }
+
+    public void setScopeParamRequired(boolean scopeParamRequired) {
+        this.scopeParamRequired = scopeParamRequired;
+    }
+
     public List<String> getCompositeRoleIds() {
         return compositeRoleIds;
     }
diff --git a/model/api/src/main/java/org/keycloak/models/entities/UserEntity.java b/model/api/src/main/java/org/keycloak/models/entities/UserEntity.java
index 8c82a8e..66020db 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/UserEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/UserEntity.java
@@ -28,6 +28,7 @@ public class UserEntity extends AbstractIdentifiableEntity {
     private List<FederatedIdentityEntity> federatedIdentities;
     private String federationLink;
     private String serviceAccountClientLink;
+    private List<OfflineUserSessionEntity> offlineUserSessions;
 
     public String getUsername() {
         return username;
@@ -157,5 +158,13 @@ public class UserEntity extends AbstractIdentifiableEntity {
     public void setServiceAccountClientLink(String serviceAccountClientLink) {
         this.serviceAccountClientLink = serviceAccountClientLink;
     }
+
+    public List<OfflineUserSessionEntity> getOfflineUserSessions() {
+        return offlineUserSessions;
+    }
+
+    public void setOfflineUserSessions(List<OfflineUserSessionEntity> offlineUserSessions) {
+        this.offlineUserSessions = offlineUserSessions;
+    }
 }
 
diff --git a/model/api/src/main/java/org/keycloak/models/IdentityProviderMapperModel.java b/model/api/src/main/java/org/keycloak/models/IdentityProviderMapperModel.java
index e3acf7f..781268e 100755
--- a/model/api/src/main/java/org/keycloak/models/IdentityProviderMapperModel.java
+++ b/model/api/src/main/java/org/keycloak/models/IdentityProviderMapperModel.java
@@ -10,7 +10,6 @@ import java.util.Map;
  * @version $Revision: 1 $
  */
 public class IdentityProviderMapperModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     protected String id;
     protected String name;
diff --git a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
index 363ae52..fa3eb71 100755
--- a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
@@ -30,7 +30,6 @@ import org.keycloak.representations.idm.IdentityProviderRepresentation;
  * @author Pedro Igor
  */
 public class IdentityProviderModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String internalId;
 
diff --git a/model/api/src/main/java/org/keycloak/models/ImpersonationConstants.java b/model/api/src/main/java/org/keycloak/models/ImpersonationConstants.java
index 274e7a6..54f212a 100755
--- a/model/api/src/main/java/org/keycloak/models/ImpersonationConstants.java
+++ b/model/api/src/main/java/org/keycloak/models/ImpersonationConstants.java
@@ -26,6 +26,7 @@ public class ImpersonationConstants {
         if (realmAdminApp.getRole(IMPERSONATION_ROLE) != null) return;
         RoleModel impersonationRole = realmAdminApp.addRole(IMPERSONATION_ROLE);
         impersonationRole.setDescription("${role_" + IMPERSONATION_ROLE + "}");
+        impersonationRole.setScopeParamRequired(false);
         adminRole.addCompositeRole(impersonationRole);
     }
 
@@ -36,6 +37,7 @@ public class ImpersonationConstants {
         if (realmAdminApp.getRole(IMPERSONATION_ROLE) != null) return;
         RoleModel impersonationRole = realmAdminApp.addRole(IMPERSONATION_ROLE);
         impersonationRole.setDescription("${role_" + IMPERSONATION_ROLE + "}");
+        impersonationRole.setScopeParamRequired(false);
         RoleModel adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
         adminRole.addCompositeRole(impersonationRole);
     }
diff --git a/model/api/src/main/java/org/keycloak/models/OfflineClientSessionModel.java b/model/api/src/main/java/org/keycloak/models/OfflineClientSessionModel.java
new file mode 100644
index 0000000..47ae23a
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/OfflineClientSessionModel.java
@@ -0,0 +1,44 @@
+package org.keycloak.models;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OfflineClientSessionModel {
+
+    private String clientSessionId;
+    private String userSessionId;
+    private String clientId;
+    private String data;
+
+    public String getClientSessionId() {
+        return clientSessionId;
+    }
+
+    public void setClientSessionId(String clientSessionId) {
+        this.clientSessionId = clientSessionId;
+    }
+
+    public String getUserSessionId() {
+        return userSessionId;
+    }
+
+    public void setUserSessionId(String userSessionId) {
+        this.userSessionId = userSessionId;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/OfflineUserSessionModel.java b/model/api/src/main/java/org/keycloak/models/OfflineUserSessionModel.java
new file mode 100644
index 0000000..9907783
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/OfflineUserSessionModel.java
@@ -0,0 +1,26 @@
+package org.keycloak.models;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OfflineUserSessionModel {
+
+    private String userSessionId;
+    private String data;
+
+    public String getUserSessionId() {
+        return userSessionId;
+    }
+
+    public void setUserSessionId(String userSessionId) {
+        this.userSessionId = userSessionId;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java b/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
index 5bdae2c..aff7d37 100755
--- a/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
+++ b/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
@@ -15,7 +15,6 @@ import java.util.regex.Pattern;
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class PasswordPolicy implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     public static final String INVALID_PASSWORD_MIN_LENGTH_MESSAGE = "invalidPasswordMinLengthMessage";
     public static final String INVALID_PASSWORD_MIN_DIGITS_MESSAGE = "invalidPasswordMinDigitsMessage";
diff --git a/model/api/src/main/java/org/keycloak/models/ProtocolMapperModel.java b/model/api/src/main/java/org/keycloak/models/ProtocolMapperModel.java
index 60d528b..06f264b 100755
--- a/model/api/src/main/java/org/keycloak/models/ProtocolMapperModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ProtocolMapperModel.java
@@ -10,7 +10,6 @@ import java.util.Map;
  * @version $Revision: 1 $
  */
 public class ProtocolMapperModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     protected String id;
     protected String name;
diff --git a/model/api/src/main/java/org/keycloak/models/RequiredCredentialModel.java b/model/api/src/main/java/org/keycloak/models/RequiredCredentialModel.java
index 84cf92c..2aea1e2 100755
--- a/model/api/src/main/java/org/keycloak/models/RequiredCredentialModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RequiredCredentialModel.java
@@ -10,7 +10,6 @@ import java.util.Map;
  * @version $Revision: 1 $
  */
 public class RequiredCredentialModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     protected String type;
     protected boolean input;
diff --git a/model/api/src/main/java/org/keycloak/models/RoleModel.java b/model/api/src/main/java/org/keycloak/models/RoleModel.java
index c296795..9904a16 100755
--- a/model/api/src/main/java/org/keycloak/models/RoleModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RoleModel.java
@@ -17,6 +17,10 @@ public interface RoleModel {
 
     void setName(String name);
 
+    boolean isScopeParamRequired();
+
+    void setScopeParamRequired(boolean scopeParamRequired);
+
     boolean isComposite();
 
     void addCompositeRole(RoleModel role);
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationMapperModel.java b/model/api/src/main/java/org/keycloak/models/UserFederationMapperModel.java
index ea08a58..e63ed2c 100644
--- a/model/api/src/main/java/org/keycloak/models/UserFederationMapperModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationMapperModel.java
@@ -7,7 +7,6 @@ import java.util.Map;
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 public class UserFederationMapperModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     protected String id;
     protected String name;
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationProviderModel.java b/model/api/src/main/java/org/keycloak/models/UserFederationProviderModel.java
index 4f5feda..9780766 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationProviderModel.java
@@ -11,7 +11,6 @@ import java.util.Map;
  * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
  */
 public class UserFederationProviderModel implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String id;
     private String providerName;
diff --git a/model/api/src/main/java/org/keycloak/models/UserModel.java b/model/api/src/main/java/org/keycloak/models/UserModel.java
index 3282e61..51e8fc4 100755
--- a/model/api/src/main/java/org/keycloak/models/UserModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserModel.java
@@ -1,5 +1,6 @@
 package org.keycloak.models;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -113,6 +114,15 @@ public interface UserModel {
     void updateConsent(UserConsentModel consent);
     boolean revokeConsentForClient(String clientInternalId);
 
+    void addOfflineUserSession(OfflineUserSessionModel offlineUserSession);
+    OfflineUserSessionModel getOfflineUserSession(String userSessionId);
+    Collection<OfflineUserSessionModel> getOfflineUserSessions();
+    boolean removeOfflineUserSession(String userSessionId);
+    void addOfflineClientSession(OfflineClientSessionModel offlineClientSession);
+    OfflineClientSessionModel getOfflineClientSession(String clientSessionId);
+    Collection<OfflineClientSessionModel> getOfflineClientSessions();
+    boolean removeOfflineClientSession(String clientSessionId);
+
     public static enum RequiredAction {
         VERIFY_EMAIL, UPDATE_PROFILE, CONFIGURE_TOTP, UPDATE_PASSWORD
     }
diff --git a/model/api/src/main/java/org/keycloak/models/UserSessionModel.java b/model/api/src/main/java/org/keycloak/models/UserSessionModel.java
index ff3f19a..12ebd70 100755
--- a/model/api/src/main/java/org/keycloak/models/UserSessionModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserSessionModel.java
@@ -40,6 +40,7 @@ public interface UserSessionModel {
     public String getNote(String name);
     public void setNote(String name, String value);
     public void removeNote(String name);
+    public Map<String, String> getNotes();
 
     State getState();
     void setState(State state);
diff --git a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
index b64ebb0..846269e 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
@@ -4,6 +4,7 @@ import org.bouncycastle.openssl.PEMWriter;
 import org.keycloak.constants.KerberosConstants;
 import org.keycloak.constants.ServiceAccountConstants;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.KeycloakSessionTask;
@@ -360,4 +361,13 @@ public final class KeycloakModelUtils {
     public static String toLowerCaseSafe(String str) {
         return str==null ? null : str.toLowerCase();
     }
+
+    public static void setupOfflineTokens(RealmModel realm) {
+        if (realm.getRole(Constants.OFFLINE_ACCESS_ROLE) == null) {
+            RoleModel role = realm.addRole(Constants.OFFLINE_ACCESS_ROLE);
+            role.setDescription("${role_offline-access}");
+            role.setScopeParamRequired(true);
+            realm.addDefaultRole(Constants.OFFLINE_ACCESS_ROLE);
+        }
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index bf2360e..b71fce9 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -89,6 +89,7 @@ public class ModelToRepresentation {
         rep.setId(role.getId());
         rep.setName(role.getName());
         rep.setDescription(role.getDescription());
+        rep.setScopeParamRequired(role.isScopeParamRequired());
         rep.setComposite(role.isComposite());
         return rep;
     }
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 811655b..77ae66e 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -181,6 +181,8 @@ public class RepresentationToModel {
                         // Application role may already exists (for example if it is defaultRole)
                         RoleModel role = roleRep.getId()!=null ? client.addRole(roleRep.getId(), roleRep.getName()) : client.addRole(roleRep.getName());
                         role.setDescription(roleRep.getDescription());
+                        boolean scopeParamRequired = roleRep.isScopeParamRequired()==null ? false : roleRep.isScopeParamRequired();
+                        role.setScopeParamRequired(scopeParamRequired);
                     }
                 }
             }
@@ -633,6 +635,8 @@ public class RepresentationToModel {
     public static void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
         RoleModel role = roleRep.getId()!=null ? newRealm.addRole(roleRep.getId(), roleRep.getName()) : newRealm.addRole(roleRep.getName());
         if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
+        boolean scopeParamRequired = roleRep.isScopeParamRequired() == null ? false : roleRep.isScopeParamRequired();
+        role.setScopeParamRequired(scopeParamRequired);
     }
 
     private static void addComposites(RoleModel role, RoleRepresentation roleRep, RealmModel realm) {
diff --git a/model/api/src/main/java/org/keycloak/models/utils/UserModelDelegate.java b/model/api/src/main/java/org/keycloak/models/utils/UserModelDelegate.java
index 4cd162b..f727c75 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/UserModelDelegate.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/UserModelDelegate.java
@@ -1,12 +1,15 @@
 package org.keycloak.models.utils;
 
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.OfflineClientSessionModel;
+import org.keycloak.models.OfflineUserSessionModel;
 import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserModel;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -255,4 +258,44 @@ public class UserModelDelegate implements UserModel {
     public void setCreatedTimestamp(Long timestamp){
         delegate.setCreatedTimestamp(timestamp);
     }
+
+    @Override
+    public void addOfflineUserSession(OfflineUserSessionModel userSession) {
+        delegate.addOfflineUserSession(userSession);
+    }
+
+    @Override
+    public OfflineUserSessionModel getOfflineUserSession(String userSessionId) {
+        return delegate.getOfflineUserSession(userSessionId);
+    }
+
+    @Override
+    public Collection<OfflineUserSessionModel> getOfflineUserSessions() {
+        return delegate.getOfflineUserSessions();
+    }
+
+    @Override
+    public boolean removeOfflineUserSession(String userSessionId) {
+        return delegate.removeOfflineUserSession(userSessionId);
+    }
+
+    @Override
+    public void addOfflineClientSession(OfflineClientSessionModel clientSession) {
+        delegate.addOfflineClientSession(clientSession);
+    }
+
+    @Override
+    public OfflineClientSessionModel getOfflineClientSession(String clientSessionId) {
+        return delegate.getOfflineClientSession(clientSessionId);
+    }
+
+    @Override
+    public Collection<OfflineClientSessionModel> getOfflineClientSessions() {
+        return delegate.getOfflineClientSessions();
+    }
+
+    @Override
+    public boolean removeOfflineClientSession(String clientSessionId) {
+        return delegate.removeOfflineClientSession(clientSessionId);
+    }
 }
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RoleAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RoleAdapter.java
index 9448def..7706459 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/RoleAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RoleAdapter.java
@@ -89,6 +89,16 @@ public class RoleAdapter implements RoleModel {
     }
 
     @Override
+    public boolean isScopeParamRequired() {
+        return role.isScopeParamRequired();
+    }
+
+    @Override
+    public void setScopeParamRequired(boolean scopeParamRequired) {
+        role.setScopeParamRequired(scopeParamRequired);
+    }
+
+    @Override
     public boolean isComposite() {
         return role.getCompositeRoleIds() != null && role.getCompositeRoleIds().size() > 0;
     }
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/UserAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/UserAdapter.java
index 7461cbd..d89ce63 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/UserAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/UserAdapter.java
@@ -22,7 +22,10 @@ import org.keycloak.models.ClientModel;
 import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
 
 import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ModelException;
 import org.keycloak.models.OTPPolicy;
+import org.keycloak.models.OfflineClientSessionModel;
+import org.keycloak.models.OfflineUserSessionModel;
 import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
@@ -32,6 +35,8 @@ import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.entities.CredentialEntity;
 import org.keycloak.models.entities.FederatedIdentityEntity;
+import org.keycloak.models.entities.OfflineClientSessionEntity;
+import org.keycloak.models.entities.OfflineUserSessionEntity;
 import org.keycloak.models.entities.RoleEntity;
 import org.keycloak.models.entities.UserEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
@@ -39,6 +44,7 @@ import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
 import org.keycloak.util.Time;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -216,7 +222,7 @@ public class UserAdapter implements UserModel, Comparable {
 
     @Override
     public Map<String, List<String>> getAttributes() {
-        return user.getAttributes()==null ? Collections.<String, List<String>>emptyMap() : Collections.unmodifiableMap((Map)user.getAttributes());
+        return user.getAttributes()==null ? Collections.<String, List<String>>emptyMap() : Collections.unmodifiableMap((Map) user.getAttributes());
     }
 
     @Override
@@ -569,6 +575,142 @@ public class UserAdapter implements UserModel, Comparable {
     }
 
     @Override
+    public void addOfflineUserSession(OfflineUserSessionModel userSession) {
+        if (user.getOfflineUserSessions() == null) {
+            user.setOfflineUserSessions(new ArrayList<OfflineUserSessionEntity>());
+        }
+
+        if (getUserSessionEntityById(userSession.getUserSessionId()) != null) {
+            throw new ModelDuplicateException("User session already exists with id " + userSession.getUserSessionId() + " for user " + user.getUsername());
+        }
+
+        OfflineUserSessionEntity entity = new OfflineUserSessionEntity();
+        entity.setUserSessionId(userSession.getUserSessionId());
+        entity.setData(userSession.getData());
+        entity.setOfflineClientSessions(new ArrayList<OfflineClientSessionEntity>());
+        user.getOfflineUserSessions().add(entity);
+    }
+
+    @Override
+    public OfflineUserSessionModel getOfflineUserSession(String userSessionId) {
+        OfflineUserSessionEntity entity = getUserSessionEntityById(userSessionId);
+        return entity==null ? null : toModel(entity);
+    }
+
+    @Override
+    public Collection<OfflineUserSessionModel> getOfflineUserSessions() {
+        if (user.getOfflineUserSessions()==null) {
+            return Collections.emptyList();
+        } else {
+            List<OfflineUserSessionModel> result = new ArrayList<>();
+            for (OfflineUserSessionEntity entity : user.getOfflineUserSessions()) {
+                result.add(toModel(entity));
+            }
+            return result;
+        }
+    }
+
+    private OfflineUserSessionModel toModel(OfflineUserSessionEntity entity) {
+        OfflineUserSessionModel model = new OfflineUserSessionModel();
+        model.setUserSessionId(entity.getUserSessionId());
+        model.setData(entity.getData());
+        return model;
+    }
+
+    @Override
+    public boolean removeOfflineUserSession(String userSessionId) {
+        OfflineUserSessionEntity entity = getUserSessionEntityById(userSessionId);
+        if (entity != null) {
+            user.getOfflineUserSessions().remove(entity);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private OfflineUserSessionEntity getUserSessionEntityById(String userSessionId) {
+        if (user.getOfflineUserSessions() != null) {
+            for (OfflineUserSessionEntity entity : user.getOfflineUserSessions()) {
+                if (entity.getUserSessionId().equals(userSessionId)) {
+                    return entity;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void addOfflineClientSession(OfflineClientSessionModel clientSession) {
+        OfflineUserSessionEntity userSessionEntity = getUserSessionEntityById(clientSession.getUserSessionId());
+        if (userSessionEntity == null) {
+            throw new ModelException("OfflineUserSession with ID " + clientSession.getUserSessionId() + " doesn't exist for user " + user.getUsername());
+        }
+
+        OfflineClientSessionEntity clEntity = new OfflineClientSessionEntity();
+        clEntity.setClientSessionId(clientSession.getClientSessionId());
+        clEntity.setClientId(clientSession.getClientId());
+        clEntity.setData(clientSession.getData());
+
+        userSessionEntity.getOfflineClientSessions().add(clEntity);
+    }
+
+    @Override
+    public OfflineClientSessionModel getOfflineClientSession(String clientSessionId) {
+        if (user.getOfflineUserSessions() != null) {
+            for (OfflineUserSessionEntity userSession : user.getOfflineUserSessions()) {
+                for (OfflineClientSessionEntity clSession : userSession.getOfflineClientSessions()) {
+                    if (clSession.getClientSessionId().equals(clientSessionId)) {
+                        return toModel(clSession, userSession.getUserSessionId());
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private OfflineClientSessionModel toModel(OfflineClientSessionEntity cls, String userSessionId) {
+        OfflineClientSessionModel model = new OfflineClientSessionModel();
+        model.setClientSessionId(cls.getClientSessionId());
+        model.setClientId(cls.getClientId());
+        model.setData(cls.getData());
+        model.setUserSessionId(userSessionId);
+        return model;
+    }
+
+    @Override
+    public Collection<OfflineClientSessionModel> getOfflineClientSessions() {
+        List<OfflineClientSessionModel> result = new ArrayList<>();
+
+        if (user.getOfflineUserSessions() != null) {
+            for (OfflineUserSessionEntity userSession : user.getOfflineUserSessions()) {
+                for (OfflineClientSessionEntity clSession : userSession.getOfflineClientSessions()) {
+                    result.add(toModel(clSession, userSession.getUserSessionId()));
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public boolean removeOfflineClientSession(String clientSessionId) {
+        if (user.getOfflineUserSessions() != null) {
+            for (OfflineUserSessionEntity userSession : user.getOfflineUserSessions()) {
+                for (OfflineClientSessionEntity clSession : userSession.getOfflineClientSessions()) {
+                    if (clSession.getClientSessionId().equals(clientSessionId)) {
+                        userSession.getOfflineClientSessions().remove(clSession);
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || !(o instanceof UserModel)) return false;
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java
index 68b31ed..df7c144 100644
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java
@@ -319,6 +319,7 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
 
     @Override
     public void preRemove(RealmModel realm, ClientModel client) {
+        realmInvalidations.add(realm.getId()); // easier to just invalidate whole realm
         getDelegate().preRemove(realm, client);
     }
 
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
index 536c2ef..861c252 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
@@ -60,6 +60,18 @@ public class RoleAdapter implements RoleModel {
     }
 
     @Override
+    public boolean isScopeParamRequired() {
+        if (updated != null) return updated.isScopeParamRequired();
+        return cached.isScopeParamRequired();
+    }
+
+    @Override
+    public void setScopeParamRequired(boolean scopeParamRequired) {
+        getDelegateForUpdate();
+        updated.setScopeParamRequired(scopeParamRequired);
+    }
+
+    @Override
     public String getId() {
         if (updated != null) return updated.getId();
         return cached.getId();
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
index 5a74b01..769f1b4 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
@@ -348,4 +348,52 @@ public class UserAdapter implements UserModel {
         getDelegateForUpdate();
         return updated.revokeConsentForClient(clientId);
     }
+
+    @Override
+    public void addOfflineUserSession(OfflineUserSessionModel userSession) {
+        getDelegateForUpdate();
+        updated.addOfflineUserSession(userSession);
+    }
+
+    @Override
+    public OfflineUserSessionModel getOfflineUserSession(String userSessionId) {
+        if (updated != null) return updated.getOfflineUserSession(userSessionId);
+        return cached.getOfflineUserSessions().get(userSessionId);
+    }
+
+    @Override
+    public Collection<OfflineUserSessionModel> getOfflineUserSessions() {
+        if (updated != null) return updated.getOfflineUserSessions();
+        return cached.getOfflineUserSessions().values();
+    }
+
+    @Override
+    public boolean removeOfflineUserSession(String userSessionId) {
+        getDelegateForUpdate();
+        return updated.removeOfflineUserSession(userSessionId);
+    }
+
+    @Override
+    public void addOfflineClientSession(OfflineClientSessionModel clientSession) {
+        getDelegateForUpdate();
+        updated.addOfflineClientSession(clientSession);
+    }
+
+    @Override
+    public OfflineClientSessionModel getOfflineClientSession(String clientSessionId) {
+        if (updated != null) return updated.getOfflineClientSession(clientSessionId);
+        return cached.getOfflineClientSessions().get(clientSessionId);
+    }
+
+    @Override
+    public Collection<OfflineClientSessionModel> getOfflineClientSessions() {
+        if (updated != null) return updated.getOfflineClientSessions();
+        return cached.getOfflineClientSessions().values();
+    }
+
+    @Override
+    public boolean removeOfflineClientSession(String clientSessionId) {
+        getDelegateForUpdate();
+        return updated.removeOfflineClientSession(clientSessionId);
+    }
 }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
index 25749c3..11447d0 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -21,7 +21,6 @@ import java.util.TreeMap;
  * @version $Revision: 1 $
  */
 public class CachedClient implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String id;
     private String clientId;
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java
index da97671..cc1a207 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java
@@ -9,8 +9,6 @@ import org.keycloak.models.RoleModel;
  */
 public class CachedClientRole extends CachedRole {
 
-    private static final long serialVersionUID = 1L;
-
     private final String idClient;
 
     public CachedClientRole(String idClient, RoleModel model, RealmModel realm) {
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index 3d96870..27bab74 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -33,7 +33,6 @@ import java.util.Set;
  * @version $Revision: 1 $
  */
 public class CachedRealm implements Serializable {
-    private static final long serialVersionUID = 1L;
 
     private String id;
     private String name;
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRole.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRole.java
index 3fb7332..1bbaa5c 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRole.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRole.java
@@ -13,12 +13,11 @@ import java.util.Set;
  */
 public class CachedRole implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     final protected String id;
     final protected String name;
     final protected String realm;
     final protected String description;
+    final protected Boolean scopeParamRequired;
     final protected boolean composite;
     final protected Set<String> composites = new HashSet<String>();
 
@@ -27,6 +26,7 @@ public class CachedRole implements Serializable {
         description = model.getDescription();
         id = model.getId();
         name = model.getName();
+        scopeParamRequired = model.isScopeParamRequired();
         this.realm = realm.getId();
         if (composite) {
             for (RoleModel child : model.getComposites()) {
@@ -52,6 +52,10 @@ public class CachedRole implements Serializable {
         return description;
     }
 
+    public Boolean isScopeParamRequired() {
+        return scopeParamRequired;
+    }
+
     public boolean isComposite() {
         return composite;
     }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java
index 9757c63..d38b6f9 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java
@@ -1,5 +1,7 @@
 package org.keycloak.models.cache.entities;
 
+import org.keycloak.models.OfflineClientSessionModel;
+import org.keycloak.models.OfflineUserSessionModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialValueModel;
@@ -7,9 +9,11 @@ import org.keycloak.models.UserModel;
 import org.keycloak.util.MultivaluedHashMap;
 
 import java.io.Serializable;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -33,6 +37,8 @@ public class CachedUser implements Serializable {
     private MultivaluedHashMap<String, String> attributes = new MultivaluedHashMap<>();
     private Set<String> requiredActions = new HashSet<>();
     private Set<String> roleMappings = new HashSet<String>();
+    private Map<String, OfflineUserSessionModel> offlineUserSessions = new HashMap<>();
+    private Map<String, OfflineClientSessionModel> offlineClientSessions = new HashMap<>();
 
     public CachedUser(RealmModel realm, UserModel user) {
         this.id = user.getId();
@@ -53,6 +59,12 @@ public class CachedUser implements Serializable {
         for (RoleModel role : user.getRoleMappings()) {
             roleMappings.add(role.getId());
         }
+        for (OfflineUserSessionModel offlineSession : user.getOfflineUserSessions()) {
+            offlineUserSessions.put(offlineSession.getUserSessionId(), offlineSession);
+        }
+        for (OfflineClientSessionModel offlineSession : user.getOfflineClientSessions()) {
+            offlineClientSessions.put(offlineSession.getClientSessionId(), offlineSession);
+        }
     }
 
     public String getId() {
@@ -118,4 +130,12 @@ public class CachedUser implements Serializable {
     public String getServiceAccountClientLink() {
         return serviceAccountClientLink;
     }
+
+    public Map<String, OfflineUserSessionModel> getOfflineUserSessions() {
+        return offlineUserSessions;
+    }
+
+    public Map<String, OfflineClientSessionModel> getOfflineClientSessions() {
+        return offlineClientSessions;
+    }
 }
diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml
index f4f9eec..4013fca 100755
--- a/model/jpa/pom.xml
+++ b/model/jpa/pom.xml
@@ -17,17 +17,14 @@
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk15on</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>net.iharder</groupId>
             <artifactId>base64</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-core</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
@@ -44,18 +41,15 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
-            <scope>provided</scope>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-entitymanager</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>resteasy-jaxrs</artifactId>
-            <scope>provided</scope>
             <exclusions>
                 <exclusion>
                     <groupId>log4j</groupId>
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OfflineClientSessionEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OfflineClientSessionEntity.java
new file mode 100644
index 0000000..23081c4
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OfflineClientSessionEntity.java
@@ -0,0 +1,81 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@NamedQueries({
+        @NamedQuery(name="deleteOfflineClientSessionsByRealm", query="delete from OfflineClientSessionEntity sess where sess.user IN (select u from UserEntity u where u.realmId=:realmId)"),
+        @NamedQuery(name="deleteOfflineClientSessionsByRealmAndLink", query="delete from OfflineClientSessionEntity sess where sess.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link)"),
+        @NamedQuery(name="deleteOfflineClientSessionsByClient", query="delete from OfflineClientSessionEntity sess where sess.clientId=:clientId")
+})
+@Table(name="OFFLINE_CLIENT_SESSION")
+@Entity
+public class OfflineClientSessionEntity {
+
+    @Id
+    @Column(name="CLIENT_SESSION_ID", length = 36)
+    protected String clientSessionId;
+
+    @Column(name="USER_SESSION_ID", length = 36)
+    protected String userSessionId;
+
+    @Column(name="CLIENT_ID", length = 36)
+    protected String clientId;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name="USER_ID")
+    protected UserEntity user;
+
+    @Column(name="DATA")
+    protected String data;
+
+    public String getClientSessionId() {
+        return clientSessionId;
+    }
+
+    public void setClientSessionId(String clientSessionId) {
+        this.clientSessionId = clientSessionId;
+    }
+
+    public String getUserSessionId() {
+        return userSessionId;
+    }
+
+    public void setUserSessionId(String userSessionId) {
+        this.userSessionId = userSessionId;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public UserEntity getUser() {
+        return user;
+    }
+
+    public void setUser(UserEntity user) {
+        this.user = user;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OfflineUserSessionEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OfflineUserSessionEntity.java
new file mode 100644
index 0000000..d2726fa
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OfflineUserSessionEntity.java
@@ -0,0 +1,59 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@NamedQueries({
+        @NamedQuery(name="deleteOfflineUserSessionsByRealm", query="delete from OfflineUserSessionEntity sess where sess.user IN (select u from UserEntity u where u.realmId=:realmId)"),
+        @NamedQuery(name="deleteOfflineUserSessionsByRealmAndLink", query="delete from OfflineUserSessionEntity sess where sess.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link)"),
+        @NamedQuery(name="deleteDetachedOfflineUserSessions", query="delete from OfflineUserSessionEntity sess where sess.userSessionId NOT IN (select c.userSessionId from OfflineClientSessionEntity c)")
+})
+@Table(name="OFFLINE_USER_SESSION")
+@Entity
+public class OfflineUserSessionEntity {
+
+    @Id
+    @Column(name="USER_SESSION_ID", length = 36)
+    protected String userSessionId;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name="USER_ID")
+    protected UserEntity user;
+
+    @Column(name="DATA")
+    protected String data;
+
+    public String getUserSessionId() {
+        return userSessionId;
+    }
+
+    public void setUserSessionId(String userSessionId) {
+        this.userSessionId = userSessionId;
+    }
+
+    public UserEntity getUser() {
+        return user;
+    }
+
+    public void setUser(UserEntity user) {
+        this.user = user;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
index 4c9edb7..437867e 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
@@ -37,6 +37,8 @@ public class RoleEntity {
     private String name;
     @Column(name = "DESCRIPTION")
     private String description;
+    @Column(name = "SCOPE_PARAM_REQUIRED")
+    private boolean scopeParamRequired;
 
     // hax! couldn't get constraint to work properly
     @Column(name = "REALM_ID")
@@ -93,6 +95,14 @@ public class RoleEntity {
         this.description = description;
     }
 
+    public boolean isScopeParamRequired() {
+        return scopeParamRequired;
+    }
+
+    public void setScopeParamRequired(boolean scopeParamRequired) {
+        this.scopeParamRequired = scopeParamRequired;
+    }
+
     public Collection<RoleEntity> getCompositeRoles() {
         return compositeRoles;
     }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
index 2da1641..24d23db 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
@@ -3,9 +3,13 @@ package org.keycloak.models.jpa.entities;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
 import javax.persistence.Column;
+import javax.persistence.ElementCollection;
 import javax.persistence.Entity;
 import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.MapKeyColumn;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
 import javax.persistence.OneToMany;
@@ -14,6 +18,8 @@ import javax.persistence.UniqueConstraint;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -83,6 +89,12 @@ public class UserEntity {
     @Column(name="SERVICE_ACCOUNT_CLIENT_LINK")
     protected String serviceAccountClientLink;
 
+    @OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="user")
+    protected Collection<OfflineUserSessionEntity> offlineUserSessions = new ArrayList<>();
+
+    @OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="user")
+    protected Collection<OfflineClientSessionEntity> offlineClientSessions = new ArrayList<>();
+
     public String getId() {
         return id;
     }
@@ -212,6 +224,22 @@ public class UserEntity {
         this.serviceAccountClientLink = serviceAccountClientLink;
     }
 
+    public Collection<OfflineUserSessionEntity> getOfflineUserSessions() {
+        return offlineUserSessions;
+    }
+
+    public void setOfflineUserSessions(Collection<OfflineUserSessionEntity> offlineUserSessions) {
+        this.offlineUserSessions = offlineUserSessions;
+    }
+
+    public Collection<OfflineClientSessionEntity> getOfflineClientSessions() {
+        return offlineClientSessions;
+    }
+
+    public void setOfflineClientSessions(Collection<OfflineClientSessionEntity> offlineClientSessions) {
+        this.offlineClientSessions = offlineClientSessions;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
index d92e93d..8cee4ea 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
@@ -169,6 +169,10 @@ public class JpaUserProvider implements UserProvider {
                 .setParameter("realmId", realm.getId()).executeUpdate();
         num = em.createNamedQuery("deleteUserAttributesByRealm")
                 .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteOfflineClientSessionsByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteOfflineUserSessionsByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
         num = em.createNamedQuery("deleteUsersByRealm")
                 .setParameter("realmId", realm.getId()).executeUpdate();
     }
@@ -195,6 +199,14 @@ public class JpaUserProvider implements UserProvider {
                 .setParameter("realmId", realm.getId())
                 .setParameter("link", link.getId())
                 .executeUpdate();
+        num = em.createNamedQuery("deleteOfflineClientSessionsByRealmAndLink")
+                .setParameter("realmId", realm.getId())
+                .setParameter("link", link.getId())
+                .executeUpdate();
+        num = em.createNamedQuery("deleteOfflineUserSessionsByRealmAndLink")
+                .setParameter("realmId", realm.getId())
+                .setParameter("link", link.getId())
+                .executeUpdate();
         num = em.createNamedQuery("deleteUsersByRealmAndLink")
                 .setParameter("realmId", realm.getId())
                 .setParameter("link", link.getId())
@@ -212,6 +224,8 @@ public class JpaUserProvider implements UserProvider {
         em.createNamedQuery("deleteUserConsentProtMappersByClient").setParameter("clientId", client.getId()).executeUpdate();
         em.createNamedQuery("deleteUserConsentRolesByClient").setParameter("clientId", client.getId()).executeUpdate();
         em.createNamedQuery("deleteUserConsentsByClient").setParameter("clientId", client.getId()).executeUpdate();
+        em.createNamedQuery("deleteOfflineClientSessionsByClient").setParameter("clientId", client.getId()).executeUpdate();
+        em.createNamedQuery("deleteDetachedOfflineUserSessions").executeUpdate();
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
index 4ab8d33..0e49d59 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
@@ -50,6 +50,16 @@ public class RoleAdapter implements RoleModel {
     }
 
     @Override
+    public boolean isScopeParamRequired() {
+        return role.isScopeParamRequired();
+    }
+
+    @Override
+    public void setScopeParamRequired(boolean scopeParamRequired) {
+        role.setScopeParamRequired(scopeParamRequired);
+    }
+
+    @Override
     public String getId() {
         return role.getId();
     }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
index 67def6b..bdcf1f1 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -2,6 +2,8 @@ package org.keycloak.models.jpa;
 
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.OTPPolicy;
+import org.keycloak.models.OfflineClientSessionModel;
+import org.keycloak.models.OfflineUserSessionModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.ModelDuplicateException;
@@ -14,6 +16,8 @@ import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.jpa.entities.CredentialEntity;
+import org.keycloak.models.jpa.entities.OfflineClientSessionEntity;
+import org.keycloak.models.jpa.entities.OfflineUserSessionEntity;
 import org.keycloak.models.jpa.entities.UserConsentEntity;
 import org.keycloak.models.jpa.entities.UserConsentProtocolMapperEntity;
 import org.keycloak.models.jpa.entities.UserConsentRoleEntity;
@@ -37,6 +41,7 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -751,6 +756,124 @@ public class UserAdapter implements UserModel {
     }
 
     @Override
+    public void addOfflineUserSession(OfflineUserSessionModel offlineSession) {
+        OfflineUserSessionEntity entity = new OfflineUserSessionEntity();
+        entity.setUser(user);
+        entity.setUserSessionId(offlineSession.getUserSessionId());
+        entity.setData(offlineSession.getData());
+        em.persist(entity);
+        user.getOfflineUserSessions().add(entity);
+        em.flush();
+    }
+
+    @Override
+    public OfflineUserSessionModel getOfflineUserSession(String userSessionId) {
+        for (OfflineUserSessionEntity entity : user.getOfflineUserSessions()) {
+            if (entity.getUserSessionId().equals(userSessionId)) {
+                return toModel(entity);
+            }
+        }
+        return null;
+    }
+
+    private OfflineUserSessionModel toModel(OfflineUserSessionEntity entity) {
+        OfflineUserSessionModel model = new OfflineUserSessionModel();
+        model.setUserSessionId(entity.getUserSessionId());
+        model.setData(entity.getData());
+        return model;
+    }
+
+    @Override
+    public Collection<OfflineUserSessionModel> getOfflineUserSessions() {
+        List<OfflineUserSessionModel> result = new LinkedList<>();
+        for (OfflineUserSessionEntity entity : user.getOfflineUserSessions()) {
+            result.add(toModel(entity));
+        }
+        return result;
+    }
+
+    @Override
+    public boolean removeOfflineUserSession(String userSessionId) {
+        OfflineUserSessionEntity found = null;
+        for (OfflineUserSessionEntity session : user.getOfflineUserSessions()) {
+            if (session.getUserSessionId().equals(userSessionId)) {
+                found = session;
+                break;
+            }
+        }
+
+        if (found == null) {
+            return false;
+        } else {
+            user.getOfflineUserSessions().remove(found);
+            em.remove(found);
+            em.flush();
+            return true;
+        }
+    }
+
+    @Override
+    public void addOfflineClientSession(OfflineClientSessionModel clientSession) {
+        OfflineClientSessionEntity entity = new OfflineClientSessionEntity();
+        entity.setUser(user);
+        entity.setClientSessionId(clientSession.getClientSessionId());
+        entity.setUserSessionId(clientSession.getUserSessionId());
+        entity.setClientId(clientSession.getClientId());
+        entity.setData(clientSession.getData());
+        em.persist(entity);
+        user.getOfflineClientSessions().add(entity);
+        em.flush();
+    }
+
+    @Override
+    public OfflineClientSessionModel getOfflineClientSession(String clientSessionId) {
+        for (OfflineClientSessionEntity entity : user.getOfflineClientSessions()) {
+            if (entity.getClientSessionId().equals(clientSessionId)) {
+                return toModel(entity);
+            }
+        }
+        return null;
+    }
+
+    private OfflineClientSessionModel toModel(OfflineClientSessionEntity entity) {
+        OfflineClientSessionModel model = new OfflineClientSessionModel();
+        model.setClientSessionId(entity.getClientSessionId());
+        model.setClientId(entity.getClientId());
+        model.setUserSessionId(entity.getUserSessionId());
+        model.setData(entity.getData());
+        return model;
+    }
+
+    @Override
+    public Collection<OfflineClientSessionModel> getOfflineClientSessions() {
+        List<OfflineClientSessionModel> result = new LinkedList<>();
+        for (OfflineClientSessionEntity entity : user.getOfflineClientSessions()) {
+            result.add(toModel(entity));
+        }
+        return result;
+    }
+
+    @Override
+    public boolean removeOfflineClientSession(String clientSessionId) {
+        OfflineClientSessionEntity found = null;
+        for (OfflineClientSessionEntity session : user.getOfflineClientSessions()) {
+            if (session.getClientSessionId().equals(clientSessionId)) {
+                found = session;
+                break;
+            }
+        }
+
+        if (found == null) {
+            return false;
+        } else {
+            user.getOfflineClientSessions().remove(found);
+            em.remove(found);
+            em.flush();
+            return true;
+        }
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || !(o instanceof UserModel)) return false;
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
index 308d9fb..14081c1 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
@@ -19,6 +19,8 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserProvider;
 import org.keycloak.models.entities.FederatedIdentityEntity;
+import org.keycloak.models.entities.OfflineClientSessionEntity;
+import org.keycloak.models.entities.OfflineUserSessionEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
 import org.keycloak.models.utils.CredentialValidation;
@@ -399,6 +401,36 @@ public class MongoUserProvider implements UserProvider {
                 .and("clientId").is(client.getId())
                 .get();
         getMongoStore().removeEntities(MongoUserConsentEntity.class, query, false, invocationContext);
+
+        // Remove all offlineClientSessions
+        query = new QueryBuilder()
+                .and("offlineUserSessions.offlineClientSessions.clientId").is(client.getId())
+                .get();
+        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, query, invocationContext);
+        for (MongoUserEntity user : users) {
+            boolean anyRemoved = false;
+            for (OfflineUserSessionEntity userSession : user.getOfflineUserSessions()) {
+                for (OfflineClientSessionEntity clientSession : userSession.getOfflineClientSessions()) {
+                    if (clientSession.getClientId().equals(client.getId())) {
+                        userSession.getOfflineClientSessions().remove(clientSession);
+                        anyRemoved = true;
+                        break;
+                    }
+                }
+
+                // Check if it was last clientSession. Then remove userSession too
+                if (userSession.getOfflineClientSessions().size() == 0) {
+                    user.getOfflineUserSessions().remove(userSession);
+                    anyRemoved = true;
+                    break;
+                }
+            }
+
+            if (anyRemoved) {
+                getMongoStore().updateEntity(user, invocationContext);
+            }
+
+        }
     }
 
     @Override
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
index 91ef361..f3d918b 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
@@ -69,6 +69,17 @@ public class RoleAdapter extends AbstractMongoAdapter<MongoRoleEntity> implement
     }
 
     @Override
+    public boolean isScopeParamRequired() {
+        return role.isScopeParamRequired();
+    }
+
+    @Override
+    public void setScopeParamRequired(boolean scopeParamRequired) {
+        role.setScopeParamRequired(scopeParamRequired);
+        updateRole();
+    }
+
+    @Override
     public boolean isComposite() {
         return role.getCompositeRoleIds() != null && role.getCompositeRoleIds().size() > 0;
     }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
index 8130ff5..a475bb6 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
@@ -8,6 +8,8 @@ import com.mongodb.QueryBuilder;
 import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.OTPPolicy;
+import org.keycloak.models.OfflineClientSessionModel;
+import org.keycloak.models.OfflineUserSessionModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.KeycloakSession;
@@ -20,6 +22,8 @@ import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.entities.CredentialEntity;
+import org.keycloak.models.entities.OfflineClientSessionEntity;
+import org.keycloak.models.entities.OfflineUserSessionEntity;
 import org.keycloak.models.entities.UserConsentEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
@@ -30,6 +34,7 @@ import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
 import org.keycloak.util.Time;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -628,6 +633,145 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
     }
 
     @Override
+    public void addOfflineUserSession(OfflineUserSessionModel userSession) {
+        if (user.getOfflineUserSessions() == null) {
+            user.setOfflineUserSessions(new ArrayList<OfflineUserSessionEntity>());
+        }
+
+        if (getUserSessionEntityById(userSession.getUserSessionId()) != null) {
+            throw new ModelDuplicateException("User session already exists with id " + userSession.getUserSessionId() + " for user " + getMongoEntity().getUsername());
+        }
+
+        OfflineUserSessionEntity entity = new OfflineUserSessionEntity();
+        entity.setUserSessionId(userSession.getUserSessionId());
+        entity.setData(userSession.getData());
+        entity.setOfflineClientSessions(new ArrayList<OfflineClientSessionEntity>());
+        user.getOfflineUserSessions().add(entity);
+        updateUser();
+    }
+
+    @Override
+    public OfflineUserSessionModel getOfflineUserSession(String userSessionId) {
+        OfflineUserSessionEntity entity = getUserSessionEntityById(userSessionId);
+        return entity==null ? null : toModel(entity);
+    }
+
+    @Override
+    public Collection<OfflineUserSessionModel> getOfflineUserSessions() {
+        if (user.getOfflineUserSessions()==null) {
+            return Collections.emptyList();
+        } else {
+            List<OfflineUserSessionModel> result = new ArrayList<>();
+            for (OfflineUserSessionEntity entity : user.getOfflineUserSessions()) {
+                result.add(toModel(entity));
+            }
+            return result;
+        }
+    }
+
+    private OfflineUserSessionModel toModel(OfflineUserSessionEntity entity) {
+        OfflineUserSessionModel model = new OfflineUserSessionModel();
+        model.setUserSessionId(entity.getUserSessionId());
+        model.setData(entity.getData());
+        return model;
+    }
+
+    @Override
+    public boolean removeOfflineUserSession(String userSessionId) {
+        OfflineUserSessionEntity entity = getUserSessionEntityById(userSessionId);
+        if (entity != null) {
+            user.getOfflineUserSessions().remove(entity);
+            updateUser();
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private OfflineUserSessionEntity getUserSessionEntityById(String userSessionId) {
+        if (user.getOfflineUserSessions() != null) {
+            for (OfflineUserSessionEntity entity : user.getOfflineUserSessions()) {
+                if (entity.getUserSessionId().equals(userSessionId)) {
+                    return entity;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void addOfflineClientSession(OfflineClientSessionModel clientSession) {
+        OfflineUserSessionEntity userSessionEntity = getUserSessionEntityById(clientSession.getUserSessionId());
+        if (userSessionEntity == null) {
+            throw new ModelException("OfflineUserSession with ID " + clientSession.getUserSessionId() + " doesn't exist for user " + getMongoEntity().getUsername());
+        }
+
+        OfflineClientSessionEntity clEntity = new OfflineClientSessionEntity();
+        clEntity.setClientSessionId(clientSession.getClientSessionId());
+        clEntity.setClientId(clientSession.getClientId());
+        clEntity.setData(clientSession.getData());
+
+        userSessionEntity.getOfflineClientSessions().add(clEntity);
+        updateUser();
+    }
+
+    @Override
+    public OfflineClientSessionModel getOfflineClientSession(String clientSessionId) {
+        if (user.getOfflineUserSessions() != null) {
+            for (OfflineUserSessionEntity userSession : user.getOfflineUserSessions()) {
+                for (OfflineClientSessionEntity clSession : userSession.getOfflineClientSessions()) {
+                    if (clSession.getClientSessionId().equals(clientSessionId)) {
+                        return toModel(clSession, userSession.getUserSessionId());
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private OfflineClientSessionModel toModel(OfflineClientSessionEntity cls, String userSessionId) {
+        OfflineClientSessionModel model = new OfflineClientSessionModel();
+        model.setClientSessionId(cls.getClientSessionId());
+        model.setClientId(cls.getClientId());
+        model.setData(cls.getData());
+        model.setUserSessionId(userSessionId);
+        return model;
+    }
+
+    @Override
+    public Collection<OfflineClientSessionModel> getOfflineClientSessions() {
+        List<OfflineClientSessionModel> result = new ArrayList<>();
+
+        if (user.getOfflineUserSessions() != null) {
+            for (OfflineUserSessionEntity userSession : user.getOfflineUserSessions()) {
+                for (OfflineClientSessionEntity clSession : userSession.getOfflineClientSessions()) {
+                    result.add(toModel(clSession, userSession.getUserSessionId()));
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public boolean removeOfflineClientSession(String clientSessionId) {
+        if (user.getOfflineUserSessions() != null) {
+            for (OfflineUserSessionEntity userSession : user.getOfflineUserSessions()) {
+                for (OfflineClientSessionEntity clSession : userSession.getOfflineClientSessions()) {
+                    if (clSession.getClientSessionId().equals(clientSessionId)) {
+                        userSession.getOfflineClientSessions().remove(clSession);
+                        updateUser();
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || !(o instanceof UserModel)) return false;
diff --git a/model/sessions-infinispan/pom.xml b/model/sessions-infinispan/pom.xml
index 3d8c256..ee64a6b 100755
--- a/model/sessions-infinispan/pom.xml
+++ b/model/sessions-infinispan/pom.xml
@@ -17,22 +17,18 @@
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-core</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-model-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-connections-infinispan</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.infinispan</groupId>
             <artifactId>infinispan-core</artifactId>
-            <scope>provided</scope>
         </dependency>
     </dependencies>
 </project>
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/UserSessionAdapter.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/UserSessionAdapter.java
index fbe8682..a9db618 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/UserSessionAdapter.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/UserSessionAdapter.java
@@ -10,6 +10,7 @@ import org.keycloak.models.sessions.infinispan.compat.entities.UserSessionEntity
 
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -144,5 +145,8 @@ public class UserSessionAdapter implements UserSessionModel {
 
     }
 
-
+    @Override
+    public Map<String, String> getNotes() {
+        return entity.getNotes();
+    }
 }
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
index 6cfc121..c7104fb 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
@@ -14,6 +14,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -110,6 +111,11 @@ public class UserSessionAdapter implements UserSessionModel {
     }
 
     @Override
+    public Map<String, String> getNotes() {
+        return entity.getNotes();
+    }
+
+    @Override
     public State getState() {
         return entity.getState();
     }

pom.xml 112(+53 -59)

diff --git a/pom.xml b/pom.xml
index c0a1cc1..bfc0c06 100755
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,7 @@
         <io.netty.version>4.0.26.Final</io.netty.version> 
         <xnio.netty.netty-xnio-transport.version>0.1.1.Final</xnio.netty.netty-xnio-transport.version>
         <hibernate.javax.persistence.version>1.0.0.Final</hibernate.javax.persistence.version>
+        <hibernate.javax.persistence.artifactId>hibernate-jpa-2.1-api</hibernate.javax.persistence.artifactId>
         <hibernate.entitymanager.version>4.3.10.Final</hibernate.entitymanager.version>
         <h2.version>1.4.187</h2.version>
         <mysql.version>5.1.29</mysql.version>
@@ -322,7 +323,7 @@
             </dependency>
             <dependency>
                 <groupId>org.hibernate.javax.persistence</groupId>
-                <artifactId>hibernate-jpa-2.1-api</artifactId>
+                <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
                 <version>${hibernate.javax.persistence.version}</version>
             </dependency>
             <dependency>
@@ -1255,6 +1256,15 @@
             <plugins>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-release-plugin</artifactId>
+                    <version>2.5.2</version>
+                    <configuration>
+                        <autoVersionSubmodules>true</autoVersionSubmodules>
+                        <tagNameFormat>@{project.version}</tagNameFormat>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-surefire-plugin</artifactId>
                     <configuration>
                         <forkMode>once</forkMode>
@@ -1349,6 +1359,48 @@
     </build>
 
     <profiles>
+        <profile>
+            <id>distribution</id>
+            <modules>
+                <module>distribution</module>
+            </modules>
+        </profile>
+
+        <profile>
+            <id>jboss-release</id>
+            <modules>
+                <module>docbook</module>
+                <module>distribution</module>
+            </modules>
+        </profile>
+
+        <profile>
+            <id>doclint-java8-disable</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <configuration>
+                            <additionalparam>-Xdoclint:none</additionalparam>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </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>
@@ -1382,63 +1434,5 @@
                 </pluginRepository>
             </pluginRepositories>
         </profile>
-        <profile>
-            <id>distribution</id>
-            <modules>
-                <module>distribution</module>
-                <module>testsuite/integration-arquillian</module>
-            </modules>
-        </profile>
-        <profile>
-            <id>jboss-release</id>
-            <modules>
-                <module>docbook</module>
-                <module>distribution</module>
-                <module>testsuite/integration-arquillian</module>
-            </modules>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-javadoc-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>aggregate</id>
-                                <phase>package</phase>
-                                <goals>
-                                    <goal>aggregate</goal>
-                                </goals>
-                                <configuration>
-                                    <minmemory>128m</minmemory>
-                                    <maxmemory>1024m</maxmemory>
-                                    <aggregate>true</aggregate>
-                                    <excludePackageNames>
-                                        se.unlogic.*:com.restfully.*:org.jboss.resteasy.examples.*:org.jboss.resteasy.tests.*
-                                    </excludePackageNames>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>          
-                </plugins>
-            </build>
-        </profile>
-        <profile>
-            <id>doclint-java8-disable</id>
-            <activation>
-                <jdk>[1.8,)</jdk>
-            </activation>
-
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-javadoc-plugin</artifactId>
-                        <configuration>
-                            <additionalparam>-Xdoclint:none</additionalparam>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
     </profiles>
 </project>
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonActionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonActionType.java
index 6936b57..81e0685 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonActionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonActionType.java
@@ -27,8 +27,6 @@ import java.io.Serializable;
  */
 public class CommonActionType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected String namespace;
 
     protected String value;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonAdviceType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonAdviceType.java
index b6d3a2b..b5beb37 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonAdviceType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonAdviceType.java
@@ -30,8 +30,6 @@ import java.util.List;
  */
 public class CommonAdviceType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<Object> advices = new ArrayList<Object>();
 
     /**
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonAssertionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonAssertionType.java
index 0637d7f..7d5d518 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonAssertionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonAssertionType.java
@@ -28,8 +28,6 @@ import java.io.Serializable;
  */
 public class CommonAssertionType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected XMLGregorianCalendar issueInstant;
 
     protected String ID;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonConditionsType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonConditionsType.java
index 4ad88a5..d69a7b9 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonConditionsType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonConditionsType.java
@@ -26,8 +26,6 @@ import java.io.Serializable;
  */
 public class CommonConditionsType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected XMLGregorianCalendar notBefore;
 
     protected XMLGregorianCalendar notOnOrAfter;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonRequestAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonRequestAbstractType.java
index 9ba0638..6dd2219 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonRequestAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonRequestAbstractType.java
@@ -30,8 +30,6 @@ import java.io.Serializable;
  */
 public abstract class CommonRequestAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected String id;
 
     protected XMLGregorianCalendar issueInstant;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonResponseType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonResponseType.java
index fbb4f65..c04fa9e 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonResponseType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonResponseType.java
@@ -28,8 +28,6 @@ import java.io.Serializable;
  */
 public class CommonResponseType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected String id;
 
     protected XMLGregorianCalendar issueInstant;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonStatusDetailType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonStatusDetailType.java
index cb427e3..6c9d6b9 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonStatusDetailType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/common/CommonStatusDetailType.java
@@ -43,8 +43,6 @@ import java.util.List;
  */
 public class CommonStatusDetailType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<Object> any = new ArrayList<Object>();
 
     /**
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ActionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ActionType.java
index 8e70a3b..6fda13a 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ActionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ActionType.java
@@ -31,5 +31,4 @@ import org.keycloak.dom.saml.common.CommonActionType;
  */
 public class SAML11ActionType extends CommonActionType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AdviceType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AdviceType.java
index 0f0dcc6..29ebad5 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AdviceType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AdviceType.java
@@ -29,5 +29,4 @@ import org.keycloak.dom.saml.common.CommonAdviceType;
  */
 public class SAML11AdviceType extends CommonAdviceType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AssertionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AssertionType.java
index 1a72241..edd3ee0 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AssertionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AssertionType.java
@@ -46,8 +46,6 @@ import java.util.List;
  */
 public class SAML11AssertionType extends CommonAssertionType {
 
-    private static final long serialVersionUID = 1L;
-
     protected int majorVersion = 1;
 
     protected int minorVersion = 1;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AttributeStatementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AttributeStatementType.java
index f572210..1ef6b82 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AttributeStatementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AttributeStatementType.java
@@ -33,8 +33,6 @@ import java.util.List;
  */
 public class SAML11AttributeStatementType extends SAML11SubjectStatementType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<SAML11AttributeType> attribute = new ArrayList<SAML11AttributeType>();
 
     public void add(SAML11AttributeType aAttribute) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AudienceRestrictionCondition.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AudienceRestrictionCondition.java
index f54ef37..33e2a94 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AudienceRestrictionCondition.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AudienceRestrictionCondition.java
@@ -33,8 +33,6 @@ import java.util.List;
  */
 public class SAML11AudienceRestrictionCondition extends SAML11ConditionAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<URI> audience = new ArrayList<URI>();
 
     public void add(URI advice) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AuthenticationStatementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AuthenticationStatementType.java
index fd2fbe0..2ee15e8 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AuthenticationStatementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AuthenticationStatementType.java
@@ -35,8 +35,6 @@ import java.util.List;
  */
 public class SAML11AuthenticationStatementType extends SAML11SubjectStatementType {
 
-    private static final long serialVersionUID = 1L;
-
     protected URI authenticationMethod;
 
     protected XMLGregorianCalendar authenticationInstant;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AuthorizationDecisionStatementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AuthorizationDecisionStatementType.java
index 970535b..c85701c 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AuthorizationDecisionStatementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11AuthorizationDecisionStatementType.java
@@ -36,8 +36,6 @@ import java.util.List;
  */
 public class SAML11AuthorizationDecisionStatementType extends SAML11SubjectStatementType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<SAML11ActionType> actions = new ArrayList<SAML11ActionType>();
 
     protected SAML11EvidenceType evidence;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionAbstractType.java
index 4208335..23f3231 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionAbstractType.java
@@ -25,5 +25,4 @@ import java.io.Serializable;
  */
 public abstract class SAML11ConditionAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionsAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionsAbstractType.java
index 9106bf2..c56143f 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionsAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionsAbstractType.java
@@ -25,5 +25,4 @@ import java.io.Serializable;
  */
 public abstract class SAML11ConditionsAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
 }
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionsType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionsType.java
index 4a4662c..8a7b33b 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionsType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionsType.java
@@ -36,8 +36,6 @@ import java.util.List;
  */
 public class SAML11ConditionsType extends CommonConditionsType {
 
-    private static final long serialVersionUID = 1L;
-
     public List<SAML11ConditionAbstractType> conditions = new ArrayList<SAML11ConditionAbstractType>();
 
     public void add(SAML11ConditionAbstractType condition) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionType.java
index f06bf32..c6a0446 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11ConditionType.java
@@ -23,5 +23,4 @@ package org.keycloak.dom.saml.v1.assertion;
  */
 public class SAML11ConditionType extends SAML11ConditionAbstractType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11DoNotCacheConditionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11DoNotCacheConditionType.java
index dc0c791..3ba9b7d 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11DoNotCacheConditionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11DoNotCacheConditionType.java
@@ -23,5 +23,4 @@ package org.keycloak.dom.saml.v1.assertion;
  */
 public class SAML11DoNotCacheConditionType extends SAML11ConditionAbstractType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11NameIdentifierType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11NameIdentifierType.java
index 0687f3c..78c3c94 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11NameIdentifierType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11NameIdentifierType.java
@@ -30,8 +30,6 @@ import java.net.URI;
  */
 public class SAML11NameIdentifierType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected String nameQualifier;
 
     protected URI format;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11StatementAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11StatementAbstractType.java
index 96f1a24..f7a7ce5 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11StatementAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11StatementAbstractType.java
@@ -25,5 +25,4 @@ import java.io.Serializable;
  */
 public abstract class SAML11StatementAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11StatementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11StatementType.java
index fa8a94d..8015555 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11StatementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11StatementType.java
@@ -23,5 +23,4 @@ package org.keycloak.dom.saml.v1.assertion;
  */
 public class SAML11StatementType extends SAML11StatementAbstractType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11SubjectStatementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11SubjectStatementType.java
index d6118ae..d1a64e5 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11SubjectStatementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/assertion/SAML11SubjectStatementType.java
@@ -28,8 +28,6 @@ package org.keycloak.dom.saml.v1.assertion;
  */
 public class SAML11SubjectStatementType extends SAML11StatementAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected SAML11SubjectType subject;
 
     public SAML11SubjectStatementType() {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AttributeQueryType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AttributeQueryType.java
index 9f13479..d79a6c3 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AttributeQueryType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AttributeQueryType.java
@@ -36,8 +36,6 @@ import java.util.List;
  */
 public class SAML11AttributeQueryType extends SAML11SubjectQueryAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<SAML11AttributeDesignatorType> attributeDesignator = new ArrayList<SAML11AttributeDesignatorType>();
 
     protected URI resource;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AuthenticationQueryType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AuthenticationQueryType.java
index d2d7bc0..ac9ff4b 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AuthenticationQueryType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AuthenticationQueryType.java
@@ -31,8 +31,6 @@ import java.net.URI;
  */
 public class SAML11AuthenticationQueryType extends SAML11SubjectQueryAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected URI authenticationMethod;
 
     public URI getAuthenticationMethod() {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AuthorizationDecisionQueryType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AuthorizationDecisionQueryType.java
index dc9d9b8..061b50a 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AuthorizationDecisionQueryType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11AuthorizationDecisionQueryType.java
@@ -39,8 +39,6 @@ import java.util.List;
  */
 public class SAML11AuthorizationDecisionQueryType extends SAML11SubjectQueryAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<SAML11ActionType> action = new ArrayList<SAML11ActionType>();
 
     protected SAML11EvidenceType evidence;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11QueryAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11QueryAbstractType.java
index 3b2c6df..88e52f4 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11QueryAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11QueryAbstractType.java
@@ -25,5 +25,4 @@ import java.io.Serializable;
  */
 public abstract class SAML11QueryAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11RequestAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11RequestAbstractType.java
index f0fa48b..c63c23f 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11RequestAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11RequestAbstractType.java
@@ -39,8 +39,6 @@ import java.util.List;
  */
 public abstract class SAML11RequestAbstractType extends CommonRequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected int majorVersion = 1;
 
     protected int minorVersion = 1;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11RequestType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11RequestType.java
index f86ff31..a7d7307 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11RequestType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11RequestType.java
@@ -36,8 +36,6 @@ import java.util.List;
  */
 public class SAML11RequestType extends SAML11RequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected SAML11QueryAbstractType query;
 
     protected List<String> assertionIDRef = new ArrayList<String>();
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11ResponseAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11ResponseAbstractType.java
index 48b5938..1afd7b7 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11ResponseAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11ResponseAbstractType.java
@@ -37,8 +37,6 @@ import java.net.URI;
  */
 public abstract class SAML11ResponseAbstractType extends CommonResponseType {
 
-    private static final long serialVersionUID = 1L;
-
     protected int majorVersion = 1;
 
     protected int minorVersion = 1;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11ResponseType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11ResponseType.java
index c07dae4..29936e5 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11ResponseType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11ResponseType.java
@@ -35,8 +35,6 @@ import java.util.List;
  */
 public class SAML11ResponseType extends SAML11ResponseAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<SAML11AssertionType> assertions = new ArrayList<SAML11AssertionType>();
 
     protected SAML11StatusType status;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11StatusCodeType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11StatusCodeType.java
index 38c56bf..3591e62 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11StatusCodeType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11StatusCodeType.java
@@ -30,8 +30,6 @@ import java.io.Serializable;
  */
 public class SAML11StatusCodeType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     public static final SAML11StatusCodeType SUCCESS = new SAML11StatusCodeType(new QName("samlp:Success"));
 
     protected SAML11StatusCodeType statusCode;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11StatusType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11StatusType.java
index 7f4b7a6..afea6a9 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11StatusType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11StatusType.java
@@ -32,8 +32,6 @@ import java.io.Serializable;
  */
 public class SAML11StatusType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected SAML11StatusCodeType statusCode;
 
     protected String statusMessage;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11SubjectQueryAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11SubjectQueryAbstractType.java
index c9ef462..0328e16 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11SubjectQueryAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v1/protocol/SAML11SubjectQueryAbstractType.java
@@ -31,8 +31,6 @@ import org.keycloak.dom.saml.v1.assertion.SAML11SubjectType;
  */
 public class SAML11SubjectQueryAbstractType extends SAML11QueryAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected SAML11SubjectType subject;
 
     public SAML11SubjectType getSubject() {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ActionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ActionType.java
index c31bf4e..98b7510 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ActionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ActionType.java
@@ -38,5 +38,4 @@ import org.keycloak.dom.saml.common.CommonActionType;
  */
 public class ActionType extends CommonActionType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AdviceType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AdviceType.java
index 8f9fc2d..31ca7d1 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AdviceType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AdviceType.java
@@ -45,5 +45,4 @@ import org.keycloak.dom.saml.common.CommonAdviceType;
  */
 public class AdviceType extends CommonAdviceType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AssertionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AssertionType.java
index 7cbd35e..b401bcb 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AssertionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AssertionType.java
@@ -43,8 +43,6 @@ import java.util.Set;
  */
 public class AssertionType extends CommonAssertionType {
 
-    private static final long serialVersionUID = 1L;
-
     private Element signature;
 
     private final String version = "2.0";
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AttributeStatementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AttributeStatementType.java
index 9b65f38..0cb88c4 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AttributeStatementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AttributeStatementType.java
@@ -45,7 +45,6 @@ import java.util.List;
  */
 public class AttributeStatementType extends StatementAbstractType {
 
-    private static final long serialVersionUID = 1L;
     protected List<ASTChoiceType> attributes = new ArrayList<ASTChoiceType>();
 
     /**
@@ -81,7 +80,6 @@ public class AttributeStatementType extends StatementAbstractType {
 
     public static class ASTChoiceType implements Serializable {
 
-        private static final long serialVersionUID = 1L;
         private AttributeType attribute;
         private EncryptedElementType encryptedAssertion;
 
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AttributeType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AttributeType.java
index c62111d..4393008 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AttributeType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AttributeType.java
@@ -50,8 +50,6 @@ import java.util.Map;
  */
 public class AttributeType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<Object> attributeValue = new ArrayList<Object>();
     protected String name;
     protected String nameFormat;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AudienceRestrictionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AudienceRestrictionType.java
index 38e1f9d..566dcbb 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AudienceRestrictionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AudienceRestrictionType.java
@@ -44,8 +44,6 @@ import java.util.List;
  */
 public class AudienceRestrictionType extends ConditionAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<URI> audience = new ArrayList<URI>();
 
     /**
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextClassRefType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextClassRefType.java
index 00c7611..e06d5ed 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextClassRefType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextClassRefType.java
@@ -28,8 +28,6 @@ import java.net.URI;
  */
 public class AuthnContextClassRefType implements URIType, Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     private final URI value;
 
     public AuthnContextClassRefType(URI value) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextDeclRefType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextDeclRefType.java
index e28ca5c..247aaeb 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextDeclRefType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextDeclRefType.java
@@ -28,7 +28,6 @@ import java.net.URI;
  */
 public class AuthnContextDeclRefType implements URIType, Serializable {
 
-    private static final long serialVersionUID = 1L;
     private URI value;
 
     public AuthnContextDeclRefType(URI value) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextDeclType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextDeclType.java
index 51749b9..bfde9d6 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextDeclType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextDeclType.java
@@ -27,8 +27,6 @@ import java.io.Serializable;
  */
 public class AuthnContextDeclType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     private Object value;
 
     public AuthnContextDeclType(Object value) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextType.java
index 0f9e18c..38069ef 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnContextType.java
@@ -60,8 +60,6 @@ import java.util.Set;
  */
 public class AuthnContextType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     private final Set<URI> authenticatingAuthority = new LinkedHashSet<URI>();
 
     private AuthnContextTypeSequence sequence;
@@ -165,8 +163,6 @@ public class AuthnContextType implements Serializable {
      */
     public class AuthnContextTypeSequence implements Serializable {
 
-        private static final long serialVersionUID = 1L;
-
         private AuthnContextClassRefType classRef;
 
         private AuthnContextDeclType authnContextDecl;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnStatementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnStatementType.java
index 33d8916..b68df7c 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnStatementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthnStatementType.java
@@ -44,8 +44,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public class AuthnStatementType extends StatementAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected SubjectLocalityType subjectLocality;
     protected AuthnContextType authnContext;
     protected XMLGregorianCalendar authnInstant;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthzDecisionStatementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthzDecisionStatementType.java
index fa8a861..fd9efb5 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthzDecisionStatementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/AuthzDecisionStatementType.java
@@ -45,7 +45,6 @@ import java.util.List;
  */
 public class AuthzDecisionStatementType extends StatementAbstractType {
 
-    private static final long serialVersionUID = 1L;
     protected List<ActionType> action = new ArrayList<ActionType>();
     protected EvidenceType evidence;
     protected String resource;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/BaseIDAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/BaseIDAbstractType.java
index 0090d23..67056bf 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/BaseIDAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/BaseIDAbstractType.java
@@ -38,7 +38,6 @@ import java.io.Serializable;
  */
 public abstract class BaseIDAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
     private String nameQualifier;
     private String sPNameQualifier;
 
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ConditionAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ConditionAbstractType.java
index 64fe2ab..c1fd41a 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ConditionAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ConditionAbstractType.java
@@ -37,5 +37,4 @@ import java.io.Serializable;
  */
 public abstract class ConditionAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ConditionsType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ConditionsType.java
index 0d77f40..65444cd 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ConditionsType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ConditionsType.java
@@ -50,8 +50,6 @@ import java.util.List;
  */
 public class ConditionsType extends CommonConditionsType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<ConditionAbstractType> conditions = new ArrayList<ConditionAbstractType>();
 
     /**
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EncryptedAssertionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EncryptedAssertionType.java
index 31cc80d..88b863d 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EncryptedAssertionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EncryptedAssertionType.java
@@ -27,8 +27,6 @@ import org.w3c.dom.Element;
  */
 public class EncryptedAssertionType extends EncryptedElementType {
 
-    private static final long serialVersionUID = 1L;
-
     public EncryptedAssertionType() {
         super();
     }
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EncryptedElementType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EncryptedElementType.java
index 19c13d6..073a8e1 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EncryptedElementType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EncryptedElementType.java
@@ -29,8 +29,6 @@ import java.io.Serializable;
  */
 public class EncryptedElementType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     /**
      * <complexType name="EncryptedElementType"> <sequence> <element ref="xenc:EncryptedData"/> <element
      * ref="xenc:EncryptedKey"
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EvidenceType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EvidenceType.java
index 47110fa..c93a168 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EvidenceType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/EvidenceType.java
@@ -48,7 +48,6 @@ import java.util.List;
  */
 public class EvidenceType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
     protected List<ChoiceType> evidences = new ArrayList<ChoiceType>();
 
     /**
@@ -80,7 +79,6 @@ public class EvidenceType implements Serializable {
 
     public static class ChoiceType implements Serializable {
 
-        private static final long serialVersionUID = 1L;
         private String AssertionIDRef;
         private URI AssertionURIRef;
         private AssertionType assertion;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/KeyInfoConfirmationDataType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/KeyInfoConfirmationDataType.java
index e11dc49..bb3ed69 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/KeyInfoConfirmationDataType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/KeyInfoConfirmationDataType.java
@@ -40,8 +40,6 @@ import org.w3c.dom.Element;
  */
 public class KeyInfoConfirmationDataType extends SubjectConfirmationDataType {
 
-    private static final long serialVersionUID = 2510471236717847074L;
-
     protected Element keyInfo;
 
     public Element getKeyInfo() {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/NameIDType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/NameIDType.java
index 3f7aec1..25a2b8a 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/NameIDType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/NameIDType.java
@@ -35,7 +35,6 @@ public class NameIDType extends BaseIDAbstractType {
      * name="SPNameQualifier" type="string" use="optional"/> </attributeGroup>
      */
 
-    private static final long serialVersionUID = 1L;
     private String value;
     private URI format;
     private String sPProvidedID;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/OneTimeUseType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/OneTimeUseType.java
index 1898c7b..0b890a7 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/OneTimeUseType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/OneTimeUseType.java
@@ -35,5 +35,4 @@ package org.keycloak.dom.saml.v2.assertion;
  */
 public class OneTimeUseType extends ConditionAbstractType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ProxyRestrictionType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ProxyRestrictionType.java
index 5072181..2c032f4 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ProxyRestrictionType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/ProxyRestrictionType.java
@@ -45,8 +45,6 @@ import java.util.List;
  */
 public class ProxyRestrictionType extends ConditionAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<URI> audience = new ArrayList<URI>();
 
     protected BigInteger count;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/StatementAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/StatementAbstractType.java
index 0230b15..3f80635 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/StatementAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/StatementAbstractType.java
@@ -38,5 +38,4 @@ import java.io.Serializable;
  */
 public abstract class StatementAbstractType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectConfirmationDataType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectConfirmationDataType.java
index 274104f..579581a 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectConfirmationDataType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectConfirmationDataType.java
@@ -50,8 +50,6 @@ import java.util.Map;
  */
 public class SubjectConfirmationDataType implements Serializable {
 
-    private static final long serialVersionUID = 7695748370849965158L;
-
     protected XMLGregorianCalendar notBefore;
 
     protected XMLGregorianCalendar notOnOrAfter;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectConfirmationType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectConfirmationType.java
index 6979022..dca866a 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectConfirmationType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectConfirmationType.java
@@ -47,7 +47,6 @@ import java.io.Serializable;
  */
 public class SubjectConfirmationType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
     protected BaseIDAbstractType baseID;
     protected NameIDType nameID;
     protected EncryptedElementType encryptedID;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectLocalityType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectLocalityType.java
index 4a8bb60..a89561d 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectLocalityType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectLocalityType.java
@@ -39,8 +39,6 @@ import java.io.Serializable;
  */
 public class SubjectLocalityType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected String address;
 
     protected String dnsName;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectType.java
index 61aeb08..c391bae 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/assertion/SubjectType.java
@@ -52,8 +52,6 @@ import java.util.List;
  */
 public class SubjectType implements Serializable {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<SubjectConfirmationType> subjectConfirmation = new ArrayList<SubjectConfirmationType>();
 
     protected STSubType subType;
@@ -114,8 +112,6 @@ public class SubjectType implements Serializable {
 
     public static class STSubType implements Serializable {
 
-        private static final long serialVersionUID = -4073731807610876524L;
-
         private BaseIDAbstractType baseID;
 
         private EncryptedElementType encryptedID;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/metadata/RequestedAttributeType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/metadata/RequestedAttributeType.java
index 2d6bb85..428ba9f 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/metadata/RequestedAttributeType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/metadata/RequestedAttributeType.java
@@ -38,8 +38,6 @@ import org.keycloak.dom.saml.v2.assertion.AttributeType;
  */
 public class RequestedAttributeType extends AttributeType {
 
-    private static final long serialVersionUID = 1L;
-
     public RequestedAttributeType(String name) {
         super(name);
     }
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ArtifactResolveType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ArtifactResolveType.java
index 6d6f3ed..90b2641 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ArtifactResolveType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ArtifactResolveType.java
@@ -40,8 +40,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public class ArtifactResolveType extends RequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected String artifact;
 
     public ArtifactResolveType(String id, XMLGregorianCalendar instant) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ArtifactResponseType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ArtifactResponseType.java
index 8ec699c..9fc3bb0 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ArtifactResponseType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ArtifactResponseType.java
@@ -40,8 +40,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public class ArtifactResponseType extends StatusResponseType {
 
-    private static final long serialVersionUID = 1L;
-
     protected Object any;
 
     public ArtifactResponseType(String id, XMLGregorianCalendar issueInstant) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AssertionIDRequestType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AssertionIDRequestType.java
index 4f3e946..fed66ee 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AssertionIDRequestType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AssertionIDRequestType.java
@@ -43,8 +43,6 @@ import java.util.List;
  */
 public class AssertionIDRequestType extends RequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<String> assertionIDRef = new ArrayList<String>();
 
     public AssertionIDRequestType(String id, XMLGregorianCalendar instant) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AttributeQueryType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AttributeQueryType.java
index 9f706a5..fdf5484 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AttributeQueryType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AttributeQueryType.java
@@ -45,8 +45,6 @@ import java.util.List;
  */
 public class AttributeQueryType extends SubjectQueryAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<AttributeType> attribute = new ArrayList<AttributeType>();
 
     public AttributeQueryType(String id, XMLGregorianCalendar instant) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthnQueryType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthnQueryType.java
index d6951eb..9898068 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthnQueryType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthnQueryType.java
@@ -41,8 +41,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public class AuthnQueryType extends SubjectQueryAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected RequestedAuthnContextType requestedAuthnContext;
 
     protected String sessionIndex;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthnRequestType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthnRequestType.java
index aa6c8d9..1491848 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthnRequestType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthnRequestType.java
@@ -56,8 +56,6 @@ import java.net.URI;
  */
 public class AuthnRequestType extends RequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected SubjectType subject;
 
     protected NameIDPolicyType nameIDPolicy;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthzDecisionQueryType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthzDecisionQueryType.java
index 20ee1b9..2c52846 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthzDecisionQueryType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/AuthzDecisionQueryType.java
@@ -49,8 +49,6 @@ import java.util.List;
  */
 public class AuthzDecisionQueryType extends SubjectQueryAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<ActionType> action = new ArrayList<ActionType>();
 
     protected EvidenceType evidence;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/LogoutRequestType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/LogoutRequestType.java
index 7249481..6db55a1 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/LogoutRequestType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/LogoutRequestType.java
@@ -54,8 +54,6 @@ import java.util.List;
  */
 public class LogoutRequestType extends RequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected BaseIDAbstractType baseID;
 
     protected NameIDType nameID;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ManageNameIDRequestType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ManageNameIDRequestType.java
index c798d12..89952bb 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ManageNameIDRequestType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ManageNameIDRequestType.java
@@ -51,8 +51,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public class ManageNameIDRequestType extends RequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected NameIDType nameID;
 
     protected EncryptedElementType encryptedID;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/NameIDMappingRequestType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/NameIDMappingRequestType.java
index d2b77b5..bd5fe43 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/NameIDMappingRequestType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/NameIDMappingRequestType.java
@@ -49,8 +49,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public class NameIDMappingRequestType extends RequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected BaseIDAbstractType baseID;
 
     protected NameIDType nameID;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/NameIDMappingResponseType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/NameIDMappingResponseType.java
index 30ce02c..dedc8ff 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/NameIDMappingResponseType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/NameIDMappingResponseType.java
@@ -44,8 +44,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public class NameIDMappingResponseType extends StatusResponseType {
 
-    private static final long serialVersionUID = 1L;
-
     protected NameIDType nameID;
 
     protected EncryptedElementType encryptedID;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/RequestAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/RequestAbstractType.java
index 5fa57ab..c670169 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/RequestAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/RequestAbstractType.java
@@ -52,8 +52,6 @@ import java.net.URI;
  */
 public abstract class RequestAbstractType extends CommonRequestAbstractType implements SAML2Object {
 
-    private static final long serialVersionUID = 1L;
-
     protected NameIDType issuer;
 
     protected ExtensionsType extensions;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ResponseType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ResponseType.java
index e4664b4..fec0f13 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ResponseType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/ResponseType.java
@@ -47,8 +47,6 @@ import java.util.List;
  */
 public class ResponseType extends StatusResponseType {
 
-    private static final long serialVersionUID = 1L;
-
     protected List<RTChoiceType> assertions = new ArrayList<ResponseType.RTChoiceType>();
 
     public ResponseType(String id, XMLGregorianCalendar issueInstant) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusDetailType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusDetailType.java
index 22f2171..2166e3a 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusDetailType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusDetailType.java
@@ -40,5 +40,4 @@ import org.keycloak.dom.saml.common.CommonStatusDetailType;
  */
 public class StatusDetailType extends CommonStatusDetailType {
 
-    private static final long serialVersionUID = 1L;
 }
\ No newline at end of file
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusResponseType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusResponseType.java
index 5cbd1d1..12235b3 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusResponseType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusResponseType.java
@@ -53,8 +53,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public class StatusResponseType extends CommonResponseType implements SAML2Object {
 
-    private static final long serialVersionUID = 1L;
-
     protected NameIDType issuer;
 
     protected ExtensionsType extensions;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/SubjectQueryAbstractType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/SubjectQueryAbstractType.java
index 31b2958..857e3e7 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/SubjectQueryAbstractType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/SubjectQueryAbstractType.java
@@ -42,8 +42,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
  */
 public abstract class SubjectQueryAbstractType extends RequestAbstractType {
 
-    private static final long serialVersionUID = 1L;
-
     protected SubjectType subject;
 
     public SubjectQueryAbstractType(String id, XMLGregorianCalendar instant) {
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ConfigurationException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ConfigurationException.java
index dd1b9dd..4a377b0 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ConfigurationException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ConfigurationException.java
@@ -26,8 +26,7 @@ import java.security.GeneralSecurityException;
  * @since May 22, 2009
  */
 public class ConfigurationException extends GeneralSecurityException {
-    private static final long serialVersionUID = 1L;
-
+    
     public ConfigurationException() {
         super();
     }
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/AssertionExpiredException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/AssertionExpiredException.java
index 3877363..746c072 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/AssertionExpiredException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/AssertionExpiredException.java
@@ -26,7 +26,6 @@ import java.security.GeneralSecurityException;
  * @since Dec 12, 2008
  */
 public class AssertionExpiredException extends GeneralSecurityException {
-    private static final long serialVersionUID = 1L;
 
     protected String id;
 
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/IssueInstantMissingException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/IssueInstantMissingException.java
index aae6dd5..e8cbd56 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/IssueInstantMissingException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/IssueInstantMissingException.java
@@ -26,7 +26,6 @@ import java.security.GeneralSecurityException;
  * @since Jun 3, 2009
  */
 public class IssueInstantMissingException extends GeneralSecurityException {
-    private static final long serialVersionUID = 1L;
 
     public IssueInstantMissingException() {
         super();
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/IssuerNotTrustedException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/IssuerNotTrustedException.java
index a9cc524..02820ee 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/IssuerNotTrustedException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/IssuerNotTrustedException.java
@@ -26,7 +26,6 @@ import java.security.GeneralSecurityException;
  * @since Jan 26, 2009
  */
 public class IssuerNotTrustedException extends GeneralSecurityException {
-    private static final long serialVersionUID = 1L;
 
     public IssuerNotTrustedException() {
         super();
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/SignatureValidationException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/SignatureValidationException.java
index 59f0b82..bfafecd 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/SignatureValidationException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/SignatureValidationException.java
@@ -26,7 +26,6 @@ import java.security.GeneralSecurityException;
  * @since Jul 28, 2011
  */
 public class SignatureValidationException extends GeneralSecurityException {
-    private static final long serialVersionUID = 1L;
 
     public SignatureValidationException() {
     }
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/WSTrustException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/WSTrustException.java
index 75f56ff..937ebb6 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/WSTrustException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/fed/WSTrustException.java
@@ -28,8 +28,6 @@ import java.security.GeneralSecurityException;
  */
 public class WSTrustException extends GeneralSecurityException {
 
-    private static final long serialVersionUID = -232066282004315310L;
-
     /**
      * <p>
      * Creates an instance of {@code WSTrustException} using the specified error message.
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ParsingException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ParsingException.java
index fb02e6f..ea1fa2b 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ParsingException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ParsingException.java
@@ -28,7 +28,6 @@ import java.security.GeneralSecurityException;
  * @since May 22, 2009
  */
 public class ParsingException extends GeneralSecurityException {
-    private static final long serialVersionUID = 1L;
 
     private Location location;
 
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/PicketLinkException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/PicketLinkException.java
index 0a6645d..799e377 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/PicketLinkException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/PicketLinkException.java
@@ -27,8 +27,6 @@ package org.keycloak.saml.common.exceptions;
  */
 public class PicketLinkException extends RuntimeException {
 
-    private static final long serialVersionUID = 789326682407249952L;
-
     public PicketLinkException() {
         super();
     }
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ProcessingException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ProcessingException.java
index 313e9e1..2b88e2f 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ProcessingException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/ProcessingException.java
@@ -26,7 +26,6 @@ import java.security.GeneralSecurityException;
  * @since May 22, 2009
  */
 public class ProcessingException extends GeneralSecurityException {
-    private static final long serialVersionUID = 1L;
 
     public ProcessingException() {
         super();
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/TrustKeyConfigurationException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/TrustKeyConfigurationException.java
index f8fc736..7f88085 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/TrustKeyConfigurationException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/TrustKeyConfigurationException.java
@@ -24,7 +24,6 @@ package org.keycloak.saml.common.exceptions;
  * @since May 22, 2009
  */
 public class TrustKeyConfigurationException extends ConfigurationException {
-    private static final long serialVersionUID = 1L;
 
     public TrustKeyConfigurationException() {
         super();
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/TrustKeyProcessingException.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/TrustKeyProcessingException.java
index e08644a..b900f0e 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/TrustKeyProcessingException.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/exceptions/TrustKeyProcessingException.java
@@ -24,7 +24,6 @@ package org.keycloak.saml.common.exceptions;
  * @since May 22, 2009
  */
 public class TrustKeyProcessingException extends ProcessingException {
-    private static final long serialVersionUID = 1L;
 
     public TrustKeyProcessingException() {
         super();

services/pom.xml 25(+0 -25)

diff --git a/services/pom.xml b/services/pom.xml
index 3f6bd51..1e2e84e 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -21,67 +21,54 @@
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk15on</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcpkix-jdk15on</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-core</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-core-jaxrs</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-connections-http-client</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-forms-common-freemarker</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-events-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-account-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-email-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-login-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-model-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-invalidation-cache-model</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-social-core</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
@@ -90,33 +77,27 @@
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-timer-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-timer-basic</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-export-import-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.jboss.spec.javax.servlet</groupId>
             <artifactId>jboss-servlet-api_3.0_spec</artifactId>
-            <scope>provided</scope>
         </dependency>
 
         <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>resteasy-jaxrs</artifactId>
-            <scope>provided</scope>
             <exclusions>
                 <exclusion>
                     <groupId>log4j</groupId>
@@ -135,32 +116,26 @@
         <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>jaxrs-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>resteasy-multipart-provider</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-core-asl</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-mapper-asl</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-xc</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.google.zxing</groupId>
             <artifactId>javase</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
diff --git a/services/src/docs/asciidoc/index.adoc b/services/src/docs/asciidoc/index.adoc
index 226d206..17ffc52 100644
--- a/services/src/docs/asciidoc/index.adoc
+++ b/services/src/docs/asciidoc/index.adoc
@@ -1,3 +1,3 @@
-include::{generated}/overview.adoc[]
+include::overview.adoc[]
 include::{generated}/paths.adoc[]
 include::{generated}/definitions.adoc[]
\ No newline at end of file
diff --git a/services/src/docs/asciidoc/overview.adoc b/services/src/docs/asciidoc/overview.adoc
new file mode 100644
index 0000000..e2457ab
--- /dev/null
+++ b/services/src/docs/asciidoc/overview.adoc
@@ -0,0 +1,13 @@
+= Keycloak Admin REST API
+
+== Overview
+This is a REST API reference for the Keycloak Admin
+
+=== Version information
+Version: 1
+
+=== URI scheme
+Host: localhost:8080
+BasePath: /auth
+Schemes: HTTP
+
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java
index 0c308ab..96f81cb 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java
@@ -27,7 +27,7 @@ import org.keycloak.services.Urls;
 
 /**
  * Client authentication based on JWT signed by client private key .
- * See <a href="https://tools.ietf.org/html/draft-jones-oauth-jwt-bearer-03">specs</a> for more details.
+ * See <a href="https://tools.ietf.org/html/rfc7519">specs</a> for more details.
  *
  * This is server side, which verifies JWT from client_assertion parameter, where the assertion was created on adapter side by
  * org.keycloak.adapters.authentication.JWTClientCredentialsProvider
diff --git a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateProfile.java b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateProfile.java
index 42c2e02..9630f3b 100755
--- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateProfile.java
+++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateProfile.java
@@ -52,7 +52,7 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact
         RealmModel realm = context.getRealm();
 
 
-        List<FormMessage> errors = Validation.validateUpdateProfileForm(formData);
+        List<FormMessage> errors = Validation.validateUpdateProfileForm(realm, formData);
         if (errors != null && !errors.isEmpty()) {
             Response challenge = context.form()
                     .setErrors(errors)
@@ -62,6 +62,28 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact
             return;
         }
 
+        if (realm.isEditUsernameAllowed()) {
+            String username = formData.getFirst("username");
+            String oldUsername = user.getUsername();
+
+            boolean usernameChanged = oldUsername != null ? !oldUsername.equals(username) : username != null;
+
+            if (usernameChanged) {
+
+                if (session.users().getUserByUsername(username, realm) != null) {
+                    Response challenge = context.form()
+                            .setError(Messages.USERNAME_EXISTS)
+                            .setFormData(formData)
+                            .createResponse(UserModel.RequiredAction.UPDATE_PROFILE);
+                    context.challenge(challenge);
+                    return;
+                }
+
+                user.setUsername(username);
+            }
+
+        }
+
         user.setFirstName(formData.getFirst("firstName"));
         user.setLastName(formData.getFirst("lastName"));
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index 15c1f46..00970e2 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -262,11 +262,14 @@ public class TokenEndpoint {
 
         AccessTokenResponse res;
         try {
-            res = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, event, headers);
+            TokenManager.RefreshResult result = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, event, headers);
+            res = result.getResponse();
 
-            UserSessionModel userSession = session.sessions().getUserSession(realm, res.getSessionState());
-            updateClientSessions(userSession.getClientSessions());
-            updateUserSessionFromClientAuth(userSession);
+            if (!result.isOfflineToken()) {
+                UserSessionModel userSession = session.sessions().getUserSession(realm, res.getSessionState());
+                updateClientSessions(userSession.getClientSessions());
+                updateUserSessionFromClientAuth(userSession);
+            }
 
         } catch (OAuthErrorException e) {
             event.error(Errors.INVALID_TOKEN);
@@ -337,6 +340,8 @@ public class TokenEndpoint {
         clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
         clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
         clientSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
+        clientSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
+
         AuthenticationFlowModel flow = realm.getDirectGrantFlow();
         String flowId = flow.getId();
         AuthenticationProcessor processor = new AuthenticationProcessor();
@@ -363,7 +368,7 @@ public class TokenEndpoint {
         updateUserSessionFromClientAuth(userSession);
 
         AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event, session, userSession, clientSession)
-                .generateAccessToken(session, scope, client, user, userSession, clientSession)
+                .generateAccessToken()
                 .generateRefreshToken()
                 .generateIDToken()
                 .build();
@@ -415,6 +420,7 @@ public class TokenEndpoint {
         ClientSessionModel clientSession = sessions.createClientSession(realm, client);
         clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
         clientSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
+        clientSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
 
         UserSessionModel userSession = sessions.createUserSession(realm, clientUser, clientUsername, clientConnection.getRemoteAddr(), ServiceAccountConstants.CLIENT_AUTH, false, null, null);
         event.session(userSession);
@@ -429,7 +435,7 @@ public class TokenEndpoint {
         updateUserSessionFromClientAuth(userSession);
 
         AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event, session, userSession, clientSession)
-                .generateAccessToken(session, scope, client, clientUser, userSession, clientSession)
+                .generateAccessToken()
                 .generateRefreshToken()
                 .generateIDToken()
                 .build();
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
index afd2a8a..714c0d1 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
@@ -20,7 +20,7 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
 
     public static final List<String> DEFAULT_ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED = list("RS256");
 
-    public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD);
+    public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS);
 
     public static final List<String> DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE);
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index 5ee8191..c43140a 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -2,9 +2,10 @@ package org.keycloak.protocol.oidc;
 
 import org.jboss.logging.Logger;
 import org.keycloak.ClientConnection;
+import org.keycloak.OAuth2Constants;
 import org.keycloak.OAuthErrorException;
-import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.jose.jws.JWSBuilder;
 import org.keycloak.jose.jws.JWSInput;
@@ -27,13 +28,20 @@ import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.IDToken;
 import org.keycloak.representations.RefreshToken;
+import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
+import org.keycloak.services.offline.OfflineTokenUtils;
+import org.keycloak.util.RefreshTokenUtil;
 import org.keycloak.util.Time;
 
 import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
@@ -85,16 +93,27 @@ public class TokenManager {
             throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled");
         }
 
-        UserSessionModel userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
-        if (!AuthenticationManager.isSessionValid(realm, userSession)) {
-            AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
-        }
+        UserSessionModel userSession = null;
         ClientSessionModel clientSession = null;
-        for (ClientSessionModel clientSessionModel : userSession.getClientSessions()) {
-            if (clientSessionModel.getId().equals(oldToken.getClientSession())) {
-                clientSession = clientSessionModel;
-                break;
+        if (RefreshTokenUtil.TOKEN_TYPE_OFFLINE.equals(oldToken.getType())) {
+
+            clientSession = OfflineTokenUtils.findOfflineClientSession(realm, user, oldToken.getClientSession(), oldToken.getSessionState());
+            if (clientSession != null) {
+                userSession = clientSession.getUserSession();
+            }
+        } else {
+            // Find userSession regularly for online tokens
+            userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
+            if (!AuthenticationManager.isSessionValid(realm, userSession)) {
+                AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
+                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
+            }
+
+            for (ClientSessionModel clientSessionModel : userSession.getClientSessions()) {
+                if (clientSessionModel.getId().equals(oldToken.getClientSession())) {
+                    clientSession = clientSessionModel;
+                    break;
+                }
             }
         }
 
@@ -117,7 +136,8 @@ public class TokenManager {
 
 
         // recreate token.
-        Set<RoleModel> requestedRoles = TokenManager.getAccess(null, clientSession.getClient(), user);
+        String scopeParam = clientSession.getNote(OAuth2Constants.SCOPE);
+        Set<RoleModel> requestedRoles = TokenManager.getAccess(scopeParam, true, clientSession.getClient(), user);
         AccessToken newToken = createClientAccessToken(session, requestedRoles, realm, client, user, userSession, clientSession);
         verifyAccess(oldToken, newToken);
 
@@ -126,10 +146,12 @@ public class TokenManager {
 
     }
 
-    public AccessTokenResponse refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel authorizedClient, String encodedRefreshToken, EventBuilder event, HttpHeaders headers) throws OAuthErrorException {
+    public RefreshResult refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel authorizedClient, String encodedRefreshToken, EventBuilder event, HttpHeaders headers) throws OAuthErrorException {
         RefreshToken refreshToken = verifyRefreshToken(realm, encodedRefreshToken);
 
-        event.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
+        event.user(refreshToken.getSubject()).session(refreshToken.getSessionState())
+                .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
+                .detail(Details.REFRESH_TOKEN_TYPE, refreshToken.getType());
 
         TokenValidation validation = validateToken(session, uriInfo, connection, realm, refreshToken, headers);
         // validate authorizedClient is same as validated client
@@ -140,11 +162,17 @@ public class TokenManager {
         int currentTime = Time.currentTime();
         validation.userSession.setLastSessionRefresh(currentTime);
 
-        AccessTokenResponse res = responseBuilder(realm, authorizedClient, event, session, validation.userSession, validation.clientSession)
+        AccessTokenResponseBuilder responseBuilder = responseBuilder(realm, authorizedClient, event, session, validation.userSession, validation.clientSession)
                 .accessToken(validation.newToken)
-                .generateIDToken()
-                .generateRefreshToken().build();
-        return res;
+                .generateIDToken();
+
+        // Don't generate refresh token again if refresh was triggered with offline token
+        if (!refreshToken.getType().equals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE)) {
+            responseBuilder.generateRefreshToken();
+        }
+
+        AccessTokenResponse res = responseBuilder.build();
+        return new RefreshResult(res, RefreshTokenUtil.TOKEN_TYPE_OFFLINE.equals(refreshToken.getType()));
     }
 
     public RefreshToken verifyRefreshToken(RealmModel realm, String encodedRefreshToken) throws OAuthErrorException {
@@ -158,7 +186,7 @@ public class TokenManager {
         } catch (Exception e) {
             throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", e);
         }
-        if (refreshToken.isExpired()) {
+        if (refreshToken.getExpiration() != 0 && refreshToken.isExpired()) {
             throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh token expired");
         }
 
@@ -172,18 +200,18 @@ public class TokenManager {
         IDToken idToken = null;
         try {
             if (!RSAProvider.verify(jws, realm.getPublicKey())) {
-                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token");
+                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid IDToken");
             }
             idToken = jws.readJsonContent(IDToken.class);
         } catch (IOException e) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", e);
+            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid IDToken", e);
         }
         if (idToken.isExpired()) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh token expired");
+            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "IDToken expired");
         }
 
         if (idToken.getIssuedAt() < realm.getNotBefore()) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
+            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale IDToken");
         }
         return idToken;
     }
@@ -206,7 +234,8 @@ public class TokenManager {
         clientSession.setUserSession(session);
         Set<String> requestedRoles = new HashSet<String>();
         // todo scope param protocol independent
-        for (RoleModel r : TokenManager.getAccess(null, clientSession.getClient(), user)) {
+        String scopeParam = clientSession.getNote(OAuth2Constants.SCOPE);
+        for (RoleModel r : TokenManager.getAccess(scopeParam, true, clientSession.getClient(), user)) {
             requestedRoles.add(r.getId());
         }
         clientSession.setRoles(requestedRoles);
@@ -242,28 +271,62 @@ public class TokenManager {
         }
     }
 
-    public static Set<RoleModel> getAccess(String scopeParam, ClientModel client, UserModel user) {
-        // todo scopeParam is ignored until we figure out a scheme that fits with openid connect
+    public static Set<RoleModel> getAccess(String scopeParam, boolean applyScopeParam, ClientModel client, UserModel user) {
         Set<RoleModel> requestedRoles = new HashSet<RoleModel>();
 
         Set<RoleModel> roleMappings = user.getRoleMappings();
-        if (client.isFullScopeAllowed()) return roleMappings;
 
-        Set<RoleModel> scopeMappings = client.getScopeMappings();
-        if (client instanceof ClientModel) {
-            scopeMappings.addAll(((ClientModel) client).getRoles());
+        if (client.isFullScopeAllowed()) {
+            requestedRoles = roleMappings;
+        } else {
+
+            Set<RoleModel> scopeMappings = client.getScopeMappings();
+            scopeMappings.addAll(client.getRoles());
+
+            for (RoleModel role : roleMappings) {
+                for (RoleModel desiredRole : scopeMappings) {
+                    Set<RoleModel> visited = new HashSet<RoleModel>();
+                    applyScope(role, desiredRole, visited, requestedRoles);
+                }
+            }
         }
 
-        for (RoleModel role : roleMappings) {
-            for (RoleModel desiredRole : scopeMappings) {
-                Set<RoleModel> visited = new HashSet<RoleModel>();
-                applyScope(role, desiredRole, visited, requestedRoles);
+        if (applyScopeParam) {
+            Collection<String> scopeParamRoles;
+            if (scopeParam != null) {
+                String[] scopes = scopeParam.split(" ");
+                scopeParamRoles = Arrays.asList(scopes);
+            } else {
+                scopeParamRoles = Collections.emptyList();
+            }
+
+            Set<RoleModel> roles = new HashSet<>();
+            for (RoleModel role : requestedRoles) {
+                String roleName = getRoleNameForScopeParam(role);
+                if (!role.isScopeParamRequired() || scopeParamRoles.contains(roleName)) {
+                    roles.add(role);
+                } else {
+                    if (logger.isTraceEnabled()) {
+                        logger.tracef("Role '%s' excluded by scope param. Client is '%s', User is '%s', Scope param is '%s' ", role.getName(), client.getClientId(), user.getUsername(), scopeParam);
+                    }
+                }
             }
+            requestedRoles = roles;
         }
 
         return requestedRoles;
     }
 
+    // For now, just use "roleName" for realm roles and "clientId/roleName" for client roles
+    private static String getRoleNameForScopeParam(RoleModel role) {
+        if (role.getContainer() instanceof RealmModel) {
+            return role.getName();
+        } else {
+            ClientModel client = (ClientModel) role.getContainer();
+            return client.getClientId() + "/" + role.getName();
+        }
+    }
+
     public void verifyAccess(AccessToken token, AccessToken newToken) throws OAuthErrorException {
         if (token.getRealmAccess() != null) {
             if (newToken.getRealmAccess() == null) throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "User no long has permission for realm roles");
@@ -409,8 +472,10 @@ public class TokenManager {
             return this;
         }
 
-        public AccessTokenResponseBuilder generateAccessToken(KeycloakSession session, String scopeParam, ClientModel client, UserModel user, UserSessionModel userSession, ClientSessionModel clientSession) {
-            Set<RoleModel> requestedRoles = getAccess(scopeParam, client, user);
+        public AccessTokenResponseBuilder generateAccessToken() {
+            UserModel user = userSession.getUser();
+            String scopeParam = clientSession.getNote(OIDCLoginProtocol.SCOPE_PARAM);
+            Set<RoleModel> requestedRoles = getAccess(scopeParam, true, client, user);
             accessToken = createClientAccessToken(session, requestedRoles, realm, client, user, userSession, clientSession);
             return this;
         }
@@ -419,10 +484,24 @@ public class TokenManager {
             if (accessToken == null) {
                 throw new IllegalStateException("accessToken not set");
             }
-            refreshToken = new RefreshToken(accessToken);
+
+            String scopeParam = clientSession.getNote(OIDCLoginProtocol.SCOPE_PARAM);
+            boolean offlineTokenRequested = RefreshTokenUtil.isOfflineTokenRequested(scopeParam);
+            if (offlineTokenRequested) {
+                if (!OfflineTokenUtils.isOfflineTokenAllowed(realm, clientSession)) {
+                    event.error(Errors.NOT_ALLOWED);
+                    throw new ErrorResponseException("not_allowed", "Offline tokens not allowed for the user or client", Response.Status.BAD_REQUEST);
+                }
+
+                refreshToken = new RefreshToken(accessToken);
+                refreshToken.type(RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+                OfflineTokenUtils.persistOfflineSession(clientSession, userSession);
+            } else {
+                refreshToken = new RefreshToken(accessToken);
+                refreshToken.expiration(Time.currentTime() + realm.getSsoSessionIdleTimeout());
+            }
             refreshToken.id(KeycloakModelUtils.generateId());
             refreshToken.issuedNow();
-            refreshToken.expiration(Time.currentTime() + realm.getSsoSessionIdleTimeout());
             return this;
         }
 
@@ -459,6 +538,7 @@ public class TokenManager {
                 } else {
                     event.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
                 }
+                event.detail(Details.REFRESH_TOKEN_TYPE, refreshToken.getType());
             }
 
             AccessTokenResponse res = new AccessTokenResponse();
@@ -489,4 +569,23 @@ public class TokenManager {
         }
     }
 
+    public class RefreshResult {
+
+        private final AccessTokenResponse response;
+        private final boolean offlineToken;
+
+        private RefreshResult(AccessTokenResponse response, boolean offlineToken) {
+            this.response = response;
+            this.offlineToken = offlineToken;
+        }
+
+        public AccessTokenResponse getResponse() {
+            return response;
+        }
+
+        public boolean isOfflineToken() {
+            return offlineToken;
+        }
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index fb0578e..958cd3e 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -27,6 +27,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.OAuthClientRepresentation;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.timer.TimerProvider;
 
 import java.util.Collections;
@@ -95,6 +96,7 @@ public class RealmManager implements RealmImporter {
         setupImpersonationService(realm);
         setupAuthenticationFlows(realm);
         setupRequiredActions(realm);
+        setupOfflineTokens(realm);
 
         return realm;
     }
@@ -107,6 +109,10 @@ public class RealmManager implements RealmImporter {
         if (realm.getRequiredActionProviders().size() == 0) DefaultRequiredActions.addActions(realm);
     }
 
+    protected void setupOfflineTokens(RealmModel realm) {
+        KeycloakModelUtils.setupOfflineTokens(realm);
+    }
+
     protected void setupAdminConsole(RealmModel realm) {
         ClientModel adminConsole = realm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
         if (adminConsole == null) adminConsole = new ClientManager(this).createClient(realm, Constants.ADMIN_CONSOLE_CLIENT_ID);
@@ -216,12 +222,14 @@ public class RealmManager implements RealmImporter {
 
             RoleModel createRealmRole = realm.addRole(AdminRoles.CREATE_REALM);
             adminRole.addCompositeRole(createRealmRole);
-            createRealmRole.setDescription("${role_"+AdminRoles.CREATE_REALM+"}");
+            createRealmRole.setDescription("${role_" + AdminRoles.CREATE_REALM + "}");
+            createRealmRole.setScopeParamRequired(false);
         } else {
             adminRealm = model.getRealmByName(Config.getAdminRealm());
             adminRole = adminRealm.getRole(AdminRoles.ADMIN);
         }
         adminRole.setDescription("${role_"+AdminRoles.ADMIN+"}");
+        adminRole.setScopeParamRequired(false);
 
         ClientModel realmAdminApp = KeycloakModelUtils.createClient(adminRealm, KeycloakModelUtils.getMasterRealmAdminApplicationClientId(realm.getName()));
         // No localized name for now
@@ -232,6 +240,7 @@ public class RealmManager implements RealmImporter {
         for (String r : AdminRoles.ALL_REALM_ROLES) {
             RoleModel role = realmAdminApp.addRole(r);
             role.setDescription("${role_"+r+"}");
+            role.setScopeParamRequired(false);
             adminRole.addCompositeRole(role);
         }
     }
@@ -249,12 +258,14 @@ public class RealmManager implements RealmImporter {
         }
         RoleModel adminRole = realmAdminClient.addRole(AdminRoles.REALM_ADMIN);
         adminRole.setDescription("${role_" + AdminRoles.REALM_ADMIN + "}");
+        adminRole.setScopeParamRequired(false);
         realmAdminClient.setBearerOnly(true);
         realmAdminClient.setFullScopeAllowed(false);
 
         for (String r : AdminRoles.ALL_REALM_ROLES) {
             RoleModel role = realmAdminClient.addRole(r);
             role.setDescription("${role_"+r+"}");
+            role.setScopeParamRequired(false);
             adminRole.addCompositeRole(role);
         }
     }
@@ -274,7 +285,9 @@ public class RealmManager implements RealmImporter {
 
             for (String role : AccountRoles.ALL) {
                 client.addDefaultRole(role);
-                client.getRole(role).setDescription("${role_"+role+"}");
+                RoleModel roleModel = client.getRole(role);
+                roleModel.setDescription("${role_" + role + "}");
+                roleModel.setScopeParamRequired(false);
             }
         }
     }
@@ -292,7 +305,9 @@ public class RealmManager implements RealmImporter {
             client.setFullScopeAllowed(false);
 
             for (String role : Constants.BROKER_SERVICE_ROLES) {
-                client.addRole(role).setDescription("${role_"+ role.toLowerCase().replaceAll("_", "-") +"}");
+                RoleModel roleModel = client.addRole(role);
+                roleModel.setDescription("${role_"+ role.toLowerCase().replaceAll("_", "-") +"}");
+                roleModel.setScopeParamRequired(false);
             }
         }
     }
@@ -329,6 +344,7 @@ public class RealmManager implements RealmImporter {
 
         if (!hasBrokerClient(rep)) setupBrokerService(realm);
         if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
+        if (!hasRealmRole(rep, Constants.OFFLINE_ACCESS_ROLE)) setupOfflineTokens(realm);
 
         RepresentationToModel.importRealm(session, rep, realm);
 
@@ -409,6 +425,20 @@ public class RealmManager implements RealmImporter {
         return false;
     }
 
+    private boolean hasRealmRole(RealmRepresentation rep, String roleName) {
+        if (rep.getRoles() == null || rep.getRoles().getRealm() == null) {
+            return false;
+        }
+
+        for (RoleRepresentation role : rep.getRoles().getRealm()) {
+            if (roleName.equals(role.getName())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     /**
      * Query users based on a search string:
      * <p/>
diff --git a/services/src/main/java/org/keycloak/services/offline/OfflineClientSessionAdapter.java b/services/src/main/java/org/keycloak/services/offline/OfflineClientSessionAdapter.java
new file mode 100644
index 0000000..50abfd4
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/offline/OfflineClientSessionAdapter.java
@@ -0,0 +1,289 @@
+package org.keycloak.services.offline;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.OfflineClientSessionModel;
+import org.keycloak.models.OfflineUserSessionModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OfflineClientSessionAdapter implements ClientSessionModel {
+
+    private final OfflineClientSessionModel model;
+    private final RealmModel realm;
+    private final ClientModel client;
+    private final OfflineUserSessionAdapter userSession;
+
+    private OfflineClientSessionData data;
+
+    public OfflineClientSessionAdapter(OfflineClientSessionModel model, RealmModel realm, ClientModel client, OfflineUserSessionAdapter userSession) {
+        this.model = model;
+        this.realm = realm;
+        this.client = client;
+        this.userSession = userSession;
+    }
+
+    // lazily init representation
+    private OfflineClientSessionData getData() {
+        if (data == null) {
+            try {
+                data = JsonSerialization.readValue(model.getData(), OfflineClientSessionData.class);
+            } catch (IOException ioe) {
+                throw new ModelException(ioe);
+            }
+        }
+
+        return data;
+    }
+
+    @Override
+    public String getId() {
+        return model.getClientSessionId();
+    }
+
+    @Override
+    public RealmModel getRealm() {
+        return realm;
+    }
+
+    @Override
+    public ClientModel getClient() {
+        return client;
+    }
+
+    @Override
+    public UserSessionModel getUserSession() {
+        return userSession;
+    }
+
+    @Override
+    public void setUserSession(UserSessionModel userSession) {
+        throw new IllegalStateException("Not supported setUserSession");
+    }
+
+    @Override
+    public String getRedirectUri() {
+        return data.getRedirectUri();
+    }
+
+    @Override
+    public void setRedirectUri(String uri) {
+        throw new IllegalStateException("Not supported setRedirectUri");
+    }
+
+    @Override
+    public int getTimestamp() {
+        return 0;
+    }
+
+    @Override
+    public void setTimestamp(int timestamp) {
+        throw new IllegalStateException("Not supported setTimestamp");
+    }
+
+    @Override
+    public String getAction() {
+        return null;
+    }
+
+    @Override
+    public void setAction(String action) {
+        throw new IllegalStateException("Not supported setAction");
+    }
+
+    @Override
+    public Set<String> getRoles() {
+        return getData().getRoles();
+    }
+
+    @Override
+    public void setRoles(Set<String> roles) {
+        throw new IllegalStateException("Not supported setRoles");
+    }
+
+    @Override
+    public Set<String> getProtocolMappers() {
+        return getData().getProtocolMappers();
+    }
+
+    @Override
+    public void setProtocolMappers(Set<String> protocolMappers) {
+        throw new IllegalStateException("Not supported setProtocolMappers");
+    }
+
+    @Override
+    public Map<String, ExecutionStatus> getExecutionStatus() {
+        return getData().getAuthenticatorStatus();
+    }
+
+    @Override
+    public void setExecutionStatus(String authenticator, ExecutionStatus status) {
+        throw new IllegalStateException("Not supported setExecutionStatus");
+    }
+
+    @Override
+    public void clearExecutionStatus() {
+        throw new IllegalStateException("Not supported clearExecutionStatus");
+    }
+
+    @Override
+    public UserModel getAuthenticatedUser() {
+        return userSession.getUser();
+    }
+
+    @Override
+    public void setAuthenticatedUser(UserModel user) {
+        throw new IllegalStateException("Not supported setAuthenticatedUser");
+    }
+
+    @Override
+    public String getAuthMethod() {
+        return getData().getAuthMethod();
+    }
+
+    @Override
+    public void setAuthMethod(String method) {
+        throw new IllegalStateException("Not supported setAuthMethod");
+    }
+
+    @Override
+    public String getNote(String name) {
+        return getData().getNotes()==null ? null : getData().getNotes().get(name);
+    }
+
+    @Override
+    public void setNote(String name, String value) {
+        throw new IllegalStateException("Not supported setNote");
+    }
+
+    @Override
+    public void removeNote(String name) {
+        throw new IllegalStateException("Not supported removeNote");
+    }
+
+    @Override
+    public Map<String, String> getNotes() {
+        return getData().getNotes();
+    }
+
+    @Override
+    public Set<String> getRequiredActions() {
+        throw new IllegalStateException("Not supported getRequiredActions");
+    }
+
+    @Override
+    public void addRequiredAction(String action) {
+        throw new IllegalStateException("Not supported addRequiredAction");
+    }
+
+    @Override
+    public void removeRequiredAction(String action) {
+        throw new IllegalStateException("Not supported removeRequiredAction");
+    }
+
+    @Override
+    public void addRequiredAction(UserModel.RequiredAction action) {
+        throw new IllegalStateException("Not supported addRequiredAction");
+    }
+
+    @Override
+    public void removeRequiredAction(UserModel.RequiredAction action) {
+        throw new IllegalStateException("Not supported removeRequiredAction");
+    }
+
+    @Override
+    public void setUserSessionNote(String name, String value) {
+        throw new IllegalStateException("Not supported setUserSessionNote");
+    }
+
+    @Override
+    public Map<String, String> getUserSessionNotes() {
+        throw new IllegalStateException("Not supported getUserSessionNotes");
+    }
+
+    @Override
+    public void clearUserSessionNotes() {
+        throw new IllegalStateException("Not supported clearUserSessionNotes");
+    }
+
+    protected static class OfflineClientSessionData {
+
+        @JsonProperty("authMethod")
+        private String authMethod;
+
+        @JsonProperty("redirectUri")
+        private String redirectUri;
+
+        @JsonProperty("protocolMappers")
+        private Set<String> protocolMappers;
+
+        @JsonProperty("roles")
+        private Set<String> roles;
+
+        @JsonProperty("notes")
+        private Map<String, String> notes;
+
+        @JsonProperty("authenticatorStatus")
+        private Map<String, ClientSessionModel.ExecutionStatus> authenticatorStatus = new HashMap<>();
+
+        public String getAuthMethod() {
+            return authMethod;
+        }
+
+        public void setAuthMethod(String authMethod) {
+            this.authMethod = authMethod;
+        }
+
+        public String getRedirectUri() {
+            return redirectUri;
+        }
+
+        public void setRedirectUri(String redirectUri) {
+            this.redirectUri = redirectUri;
+        }
+
+        public Set<String> getProtocolMappers() {
+            return protocolMappers;
+        }
+
+        public void setProtocolMappers(Set<String> protocolMappers) {
+            this.protocolMappers = protocolMappers;
+        }
+
+        public Set<String> getRoles() {
+            return roles;
+        }
+
+        public void setRoles(Set<String> roles) {
+            this.roles = roles;
+        }
+
+        public Map<String, String> getNotes() {
+            return notes;
+        }
+
+        public void setNotes(Map<String, String> notes) {
+            this.notes = notes;
+        }
+
+        public Map<String, ClientSessionModel.ExecutionStatus> getAuthenticatorStatus() {
+            return authenticatorStatus;
+        }
+
+        public void setAuthenticatorStatus(Map<String, ClientSessionModel.ExecutionStatus> authenticatorStatus) {
+            this.authenticatorStatus = authenticatorStatus;
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/offline/OfflineTokenUtils.java b/services/src/main/java/org/keycloak/services/offline/OfflineTokenUtils.java
new file mode 100644
index 0000000..b4900c1
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/offline/OfflineTokenUtils.java
@@ -0,0 +1,191 @@
+package org.keycloak.services.offline;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.OfflineClientSessionModel;
+import org.keycloak.models.OfflineUserSessionModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * TODO: Change to utils?
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OfflineTokenUtils {
+
+    protected static Logger logger = Logger.getLogger(OfflineTokenUtils.class);
+
+    public static void persistOfflineSession(ClientSessionModel clientSession, UserSessionModel userSession) {
+        UserModel user = userSession.getUser();
+        ClientModel client = clientSession.getClient();
+
+        // First verify if we already have offlineToken for this user+client . If yes, then invalidate it (This is to avoid leaks)
+        Collection<OfflineClientSessionModel> clientSessions = user.getOfflineClientSessions();
+        for (OfflineClientSessionModel existing : clientSessions) {
+            if (existing.getClientId().equals(client.getId())) {
+                if (logger.isTraceEnabled()) {
+                    logger.tracef("Removing existing offline token for user '%s' and client '%s' . ClientSessionID was '%s' . Offline token will be replaced with new one",
+                            user.getUsername(), client.getClientId(), existing.getClientSessionId());
+                }
+
+                user.removeOfflineClientSession(existing.getClientSessionId());
+
+                // Check if userSession is ours. If not, then check if it has other clientSessions and remove it otherwise
+                if (!existing.getUserSessionId().equals(userSession.getId())) {
+                    checkUserSessionHasClientSessions(user, existing.getUserSessionId());
+                }
+            }
+        }
+
+        // Verify if we already have UserSession with this ID. If yes, don't create another one
+        OfflineUserSessionModel userSessionRep = user.getOfflineUserSession(userSession.getId());
+        if (userSessionRep == null) {
+            createOfflineUserSession(user, userSession);
+        }
+
+        // Create clientRep and save to DB.
+        createOfflineClientSession(user, clientSession, userSession);
+    }
+
+    // userSessionId is provided from offline token. It's used just to verify if it match the ID from clientSession representation
+    public static ClientSessionModel findOfflineClientSession(RealmModel realm, UserModel user, String clientSessionId, String userSessionId) {
+        OfflineClientSessionModel clientSession = user.getOfflineClientSession(clientSessionId);
+        if (clientSession == null) {
+            return null;
+        }
+
+        if (!userSessionId.equals(clientSession.getUserSessionId())) {
+            throw new ModelException("User session don't match. Offline client session " + clientSession.getClientSessionId() + ", It's user session " + clientSession.getUserSessionId() +
+                    "  Wanted user session: " + userSessionId);
+        }
+
+        OfflineUserSessionModel userSession = user.getOfflineUserSession(userSessionId);
+        if (userSession == null) {
+            throw new ModelException("Found clientSession " + clientSessionId + " but not userSession " + userSessionId);
+        }
+
+        OfflineUserSessionAdapter userSessionAdapter = new OfflineUserSessionAdapter(userSession, user);
+
+        ClientModel client = realm.getClientById(clientSession.getClientId());
+        OfflineClientSessionAdapter clientSessionAdapter = new OfflineClientSessionAdapter(clientSession, realm, client, userSessionAdapter);
+
+        return clientSessionAdapter;
+    }
+
+    public static Set<ClientModel> findClientsWithOfflineToken(RealmModel realm, UserModel user) {
+        Collection<OfflineClientSessionModel> clientSessions = user.getOfflineClientSessions();
+        Set<ClientModel> clients = new HashSet<>();
+        for (OfflineClientSessionModel clientSession : clientSessions) {
+            ClientModel client = realm.getClientById(clientSession.getClientId());
+            clients.add(client);
+        }
+        return clients;
+    }
+
+    public static boolean revokeOfflineToken(UserModel user, ClientModel client) {
+        Collection<OfflineClientSessionModel> clientSessions = user.getOfflineClientSessions();
+        boolean anyRemoved = false;
+        for (OfflineClientSessionModel clientSession : clientSessions) {
+            if (clientSession.getClientId().equals(client.getId())) {
+                if (logger.isTraceEnabled()) {
+                    logger.tracef("Removing existing offline token for user '%s' and client '%s' . ClientSessionID was '%s' .",
+                            user.getUsername(), client.getClientId(), clientSession.getClientSessionId());
+                }
+
+                user.removeOfflineClientSession(clientSession.getClientSessionId());
+                checkUserSessionHasClientSessions(user, clientSession.getUserSessionId());
+                anyRemoved = true;
+            }
+        }
+
+        return anyRemoved;
+    }
+
+    public static boolean isOfflineTokenAllowed(RealmModel realm, ClientSessionModel clientSession) {
+        RoleModel offlineAccessRole = realm.getRole(Constants.OFFLINE_ACCESS_ROLE);
+        if (offlineAccessRole == null) {
+            logger.warnf("Role '%s' not available in realm", Constants.OFFLINE_ACCESS_ROLE);
+            return false;
+        }
+
+        return clientSession.getRoles().contains(offlineAccessRole.getId());
+    }
+
+    private static void createOfflineUserSession(UserModel user, UserSessionModel userSession) {
+        if (logger.isTraceEnabled()) {
+            logger.tracef("Creating new offline user session. UserSessionID: '%s' , Username: '%s'", userSession.getId(), user.getUsername());
+        }
+        OfflineUserSessionAdapter.OfflineUserSessionData rep = new OfflineUserSessionAdapter.OfflineUserSessionData();
+        rep.setBrokerUserId(userSession.getBrokerUserId());
+        rep.setBrokerSessionId(userSession.getBrokerSessionId());
+        rep.setIpAddress(userSession.getIpAddress());
+        rep.setAuthMethod(userSession.getAuthMethod());
+        rep.setRememberMe(userSession.isRememberMe());
+        rep.setStarted(userSession.getStarted());
+        rep.setNotes(userSession.getNotes());
+
+        try {
+            String stringRep = JsonSerialization.writeValueAsString(rep);
+            OfflineUserSessionModel sessionModel = new OfflineUserSessionModel();
+            sessionModel.setUserSessionId(userSession.getId());
+            sessionModel.setData(stringRep);
+            user.addOfflineUserSession(sessionModel);
+        } catch (IOException ioe) {
+            throw new ModelException(ioe);
+        }
+    }
+
+    private static void createOfflineClientSession(UserModel user, ClientSessionModel clientSession, UserSessionModel userSession) {
+        if (logger.isTraceEnabled()) {
+            logger.tracef("Creating new offline token client session. ClientSessionId: '%s', UserSessionID: '%s' , Username: '%s', Client: '%s'" ,
+                    clientSession.getId(), userSession.getId(), user.getUsername(), clientSession.getClient().getClientId());
+        }
+        OfflineClientSessionAdapter.OfflineClientSessionData rep = new OfflineClientSessionAdapter.OfflineClientSessionData();
+        rep.setAuthMethod(clientSession.getAuthMethod());
+        rep.setRedirectUri(clientSession.getRedirectUri());
+        rep.setProtocolMappers(clientSession.getProtocolMappers());
+        rep.setRoles(clientSession.getRoles());
+        rep.setNotes(clientSession.getNotes());
+        rep.setAuthenticatorStatus(clientSession.getExecutionStatus());
+
+        try {
+            String stringRep = JsonSerialization.writeValueAsString(rep);
+            OfflineClientSessionModel clsModel = new OfflineClientSessionModel();
+            clsModel.setClientSessionId(clientSession.getId());
+            clsModel.setClientId(clientSession.getClient().getId());
+            clsModel.setUserSessionId(userSession.getId());
+            clsModel.setData(stringRep);
+            user.addOfflineClientSession(clsModel);
+        } catch (IOException ioe) {
+            throw new ModelException(ioe);
+        }
+    }
+
+    // Check if userSession has any offline clientSessions attached to it. Remove userSession if not
+    private static void checkUserSessionHasClientSessions(UserModel user, String userSessionId) {
+        Collection<OfflineClientSessionModel> clientSessions = user.getOfflineClientSessions();
+
+        for (OfflineClientSessionModel clientSession : clientSessions) {
+            if (clientSession.getUserSessionId().equals(userSessionId)) {
+                return;
+            }
+        }
+
+        if (logger.isTraceEnabled()) {
+            logger.tracef("Removing offline userSession for user %s as it doesn't have any client sessions attached. UserSessionID: %s", user.getUsername(), userSessionId);
+        }
+        user.removeOfflineUserSession(userSessionId);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/offline/OfflineUserSessionAdapter.java b/services/src/main/java/org/keycloak/services/offline/OfflineUserSessionAdapter.java
new file mode 100644
index 0000000..bd01d38
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/offline/OfflineUserSessionAdapter.java
@@ -0,0 +1,215 @@
+package org.keycloak.services.offline;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.OfflineUserSessionModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OfflineUserSessionAdapter implements UserSessionModel {
+
+    private final OfflineUserSessionModel model;
+    private final UserModel user;
+
+    private OfflineUserSessionData data;
+
+    public OfflineUserSessionAdapter(OfflineUserSessionModel model, UserModel user) {
+        this.model = model;
+        this.user = user;
+    }
+
+    // lazily init representation
+    private OfflineUserSessionData getData() {
+        if (data == null) {
+            try {
+                data = JsonSerialization.readValue(model.getData(), OfflineUserSessionData.class);
+            } catch (IOException ioe) {
+                throw new ModelException(ioe);
+            }
+        }
+
+        return data;
+    }
+
+    @Override
+    public String getId() {
+        return model.getUserSessionId();
+    }
+
+    @Override
+    public String getBrokerSessionId() {
+        return getData().getBrokerSessionId();
+    }
+
+    @Override
+    public String getBrokerUserId() {
+        return getData().getBrokerUserId();
+    }
+
+    @Override
+    public UserModel getUser() {
+        return user;
+    }
+
+    @Override
+    public String getLoginUsername() {
+        return user.getUsername();
+    }
+
+    @Override
+    public String getIpAddress() {
+        return getData().getIpAddress();
+    }
+
+    @Override
+    public String getAuthMethod() {
+        return getData().getAuthMethod();
+    }
+
+    @Override
+    public boolean isRememberMe() {
+        return getData().isRememberMe();
+    }
+
+    @Override
+    public int getStarted() {
+        return getData().getStarted();
+    }
+
+    @Override
+    public int getLastSessionRefresh() {
+        return 0;
+    }
+
+    @Override
+    public void setLastSessionRefresh(int seconds) {
+        // Ignore
+    }
+
+    @Override
+    public List<ClientSessionModel> getClientSessions() {
+        throw new IllegalStateException("Not yet supported");
+    }
+
+    @Override
+    public String getNote(String name) {
+        return getData().getNotes()==null ? null : getData().getNotes().get(name);
+    }
+
+    @Override
+    public void setNote(String name, String value) {
+        throw new IllegalStateException("Illegal to set note offline session");
+
+    }
+
+    @Override
+    public void removeNote(String name) {
+        throw new IllegalStateException("Illegal to remove note from offline session");
+    }
+
+    @Override
+    public Map<String, String> getNotes() {
+        return getData().getNotes();
+    }
+
+    @Override
+    public State getState() {
+        return null;
+    }
+
+    @Override
+    public void setState(State state) {
+        throw new IllegalStateException("Illegal to set state on offline session");
+    }
+
+
+    protected static class OfflineUserSessionData {
+
+        @JsonProperty("brokerSessionId")
+        private String brokerSessionId;
+
+        @JsonProperty("brokerUserId")
+        private String brokerUserId;
+
+        @JsonProperty("ipAddress")
+        private String ipAddress;
+
+        @JsonProperty("authMethod")
+        private String authMethod;
+
+        @JsonProperty("rememberMe")
+        private boolean rememberMe;
+
+        @JsonProperty("started")
+        private int started;
+
+        @JsonProperty("notes")
+        private Map<String, String> notes;
+
+        public String getBrokerSessionId() {
+            return brokerSessionId;
+        }
+
+        public void setBrokerSessionId(String brokerSessionId) {
+            this.brokerSessionId = brokerSessionId;
+        }
+
+        public String getBrokerUserId() {
+            return brokerUserId;
+        }
+
+        public void setBrokerUserId(String brokerUserId) {
+            this.brokerUserId = brokerUserId;
+        }
+
+        public String getIpAddress() {
+            return ipAddress;
+        }
+
+        public void setIpAddress(String ipAddress) {
+            this.ipAddress = ipAddress;
+        }
+
+        public String getAuthMethod() {
+            return authMethod;
+        }
+
+        public void setAuthMethod(String authMethod) {
+            this.authMethod = authMethod;
+        }
+
+        public boolean isRememberMe() {
+            return rememberMe;
+        }
+
+        public void setRememberMe(boolean rememberMe) {
+            this.rememberMe = rememberMe;
+        }
+
+        public int getStarted() {
+            return started;
+        }
+
+        public void setStarted(int started) {
+            this.started = started;
+        }
+
+        public Map<String, String> getNotes() {
+            return notes;
+        }
+
+        public void setNotes(Map<String, String> notes) {
+            this.notes = notes;
+        }
+
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 1756f12..3b6edea 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -46,7 +46,6 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.CredentialValidation;
 import org.keycloak.models.utils.FormMessage;
 import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.models.utils.TimeBasedOTP;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.utils.RedirectUtils;
 import org.keycloak.representations.idm.CredentialRepresentation;
@@ -58,6 +57,7 @@ import org.keycloak.services.managers.Auth;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.messages.Messages;
+import org.keycloak.services.offline.OfflineTokenUtils;
 import org.keycloak.services.util.ResolveRelative;
 import org.keycloak.services.validation.Validation;
 import org.keycloak.util.UriUtils;
@@ -486,6 +486,7 @@ public class AccountService extends AbstractSecuredLocalService {
         // Revoke grant in UserModel
         UserModel user = auth.getUser();
         user.revokeConsentForClient(client.getId());
+        OfflineTokenUtils.revokeOfflineToken(user, client);
 
         // Logout clientSessions for this user and client
         AuthenticationManager.backchannelUserFromClient(session, realm, user, client, uriInfo, headers);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index bab74d6..fda0ee3 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -111,7 +111,7 @@ public class RealmAdminResource {
      * @return
      */
     @Path("attack-detection")
-    public AttackDetectionResource getClientImporter() {
+    public AttackDetectionResource getAttackDetection() {
         AttackDetectionResource resource = new AttackDetectionResource(auth, realm, adminEvent);
         ResteasyProviderFactory.getInstance().injectProperties(resource);
         return resource;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
index d0fb521..18e6df5 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
@@ -144,51 +144,6 @@ public class RealmsAdminResource {
         }
     }
 
-    /**
-     * Import a realm from uploaded JSON file
-     *
-     * The posted represenation is expected to be a multipart/form-data encapsulation
-     * of a JSON file.  The same format a browser would use when uploading a file.
-     *
-     * @param uriInfo
-     * @param input multipart/form data
-     * @return
-     * @throws IOException
-     */
-    @POST
-    @Consumes(MediaType.MULTIPART_FORM_DATA)
-    public Response uploadRealm(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
-        RealmManager realmManager = new RealmManager(session);
-        realmManager.setContextPath(keycloak.getContextPath());
-        if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
-            throw new ForbiddenException();
-        }
-        if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
-            throw new ForbiddenException();
-        }
-
-        Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
-        List<InputPart> inputParts = uploadForm.get("file");
-        RealmRepresentation rep = null;
-        
-        for (InputPart inputPart : inputParts) {
-            // inputPart.getBody doesn't work as content-type is wrong, and inputPart.setMediaType is not supported on AS7 (RestEasy 2.3.2.Final)
-            rep = JsonSerialization.readValue(inputPart.getBodyAsString(), RealmRepresentation.class);
-
-            RealmModel realm = realmManager.importRealm(rep);
-
-            grantPermissionsToRealmCreator(realm);
-            
-            URI location = null;
-            if (inputParts.size() == 1) {
-                location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build();
-                return Response.created(location).build();
-            }
-        }
-        
-        return Response.noContent().build();
-    }
-
     private void grantPermissionsToRealmCreator(RealmModel realm) {
         if (auth.hasRealmRole(AdminRoles.ADMIN)) {
             return;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
index 168ff47..879ff6f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
@@ -82,6 +82,8 @@ public class RoleContainerResource extends RoleResource {
         try {
             RoleModel role = roleContainer.addRole(rep.getName());
             role.setDescription(rep.getDescription());
+            boolean scopeParamRequired = rep.isScopeParamRequired()==null ? false : rep.isScopeParamRequired();
+            role.setScopeParamRequired(scopeParamRequired);
 
             adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, role.getId()).representation(rep).success();
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
index 827b817..3635da8 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
@@ -38,6 +38,7 @@ public abstract class RoleResource {
     protected void updateRole(RoleRepresentation rep, RoleModel role) {
         role.setName(rep.getName());
         role.setDescription(rep.getDescription());
+        if (rep.isScopeParamRequired() != null) role.setScopeParamRequired(rep.isScopeParamRequired());
     }
 
     protected void addComposites(AdminEventBuilder adminEvent, UriInfo uriInfo, List<RoleRepresentation> roles, RoleModel role) {
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 166fa4b..599d0b2 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -151,7 +151,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 95d644e..9458998 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -646,7 +646,7 @@ public class AccountTest {
         }
     }
 
-    // More tests (including revoke) are in OAuthGrantTest
+    // More tests (including revoke) are in OAuthGrantTest and OfflineTokenTest
     @Test
     public void applications() {
         applicationsPage.open();
@@ -668,7 +668,8 @@ public class AccountTest {
         Assert.assertTrue(accountEntry.getProtocolMappersGranted().contains("Full Access"));
 
         AccountApplicationsPage.AppEntry testAppEntry = apps.get("test-app");
-        Assert.assertEquals(4, testAppEntry.getRolesAvailable().size());
+        Assert.assertEquals(5, testAppEntry.getRolesAvailable().size());
+        Assert.assertTrue(testAppEntry.getRolesAvailable().contains("Offline access"));
         Assert.assertTrue(testAppEntry.getRolesGranted().contains("Full Access"));
         Assert.assertTrue(testAppEntry.getProtocolMappersGranted().contains("Full Access"));
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
index 868a76c..47b4e1d 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
@@ -33,11 +33,8 @@ import org.keycloak.models.UserModel.RequiredAction;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.OAuthClient;
-import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.*;
 import org.keycloak.testsuite.pages.AppPage.RequestType;
-import org.keycloak.testsuite.pages.LoginPage;
-import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
-import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
 import org.keycloak.testsuite.rule.WebResource;
@@ -83,7 +80,7 @@ public class RequiredActionMultipleActionsTest {
     protected LoginPasswordUpdatePage changePasswordPage;
 
     @WebResource
-    protected LoginUpdateProfilePage updateProfilePage;
+    protected LoginUpdateProfileEditUsernameAllowedPage updateProfilePage;
 
     @Test
     public void updateProfileAndPassword() throws Exception {
@@ -121,7 +118,7 @@ public class RequiredActionMultipleActionsTest {
     }
 
     public String updateProfile(String sessionId) {
-        updateProfilePage.update("New first", "New last", "new@email.com");
+        updateProfilePage.update("New first", "New last", "new@email.com", "test-user@localhost");
 
         AssertEvents.ExpectedEvent expectedEvent = events.expectRequiredAction(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, "test-user@localhost").detail(Details.UPDATED_EMAIL, "new@email.com");
         if (sessionId != null) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
index e3d6ac9..492cd4b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
@@ -21,11 +21,7 @@
  */
 package org.keycloak.testsuite.actions;
 
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.*;
 import org.keycloak.events.Details;
 import org.keycloak.events.EventType;
 import org.keycloak.models.RealmModel;
@@ -36,7 +32,7 @@ import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.pages.AppPage;
 import org.keycloak.testsuite.pages.AppPage.RequestType;
 import org.keycloak.testsuite.pages.LoginPage;
-import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
+import org.keycloak.testsuite.pages.LoginUpdateProfileEditUsernameAllowedPage;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
@@ -66,7 +62,7 @@ public class RequiredActionUpdateProfileTest {
     protected LoginPage loginPage;
 
     @WebResource
-    protected LoginUpdateProfilePage updateProfilePage;
+    protected LoginUpdateProfileEditUsernameAllowedPage updateProfilePage;
 
     @Before
     public void before() {
@@ -75,6 +71,8 @@ public class RequiredActionUpdateProfileTest {
             public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) {
                 UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm);
                 user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
+                UserModel anotherUser = manager.getSession().users().getUserByEmail("john-doh@localhost", appRealm);
+                anotherUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
             }
         });
     }
@@ -87,7 +85,7 @@ public class RequiredActionUpdateProfileTest {
 
         updateProfilePage.assertCurrent();
 
-        updateProfilePage.update("New first", "New last", "new@email.com");
+        updateProfilePage.update("New first", "New last", "new@email.com", "test-user@localhost");
 
         String sessionId = events.expectRequiredAction(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, "test-user@localhost").detail(Details.UPDATED_EMAIL, "new@email.com").assertEvent().getSessionId();
         events.expectRequiredAction(EventType.UPDATE_PROFILE).session(sessionId).assertEvent();
@@ -101,6 +99,41 @@ public class RequiredActionUpdateProfileTest {
         Assert.assertEquals("New first", user.getFirstName());
         Assert.assertEquals("New last", user.getLastName());
         Assert.assertEquals("new@email.com", user.getEmail());
+        Assert.assertEquals("test-user@localhost", user.getUsername());
+    }
+
+    @Test
+    public void updateUsername() {
+        loginPage.open();
+
+        loginPage.login("john-doh@localhost", "password");
+
+        String userId = keycloakRule.getUser("test", "john-doh@localhost").getId();
+
+        updateProfilePage.assertCurrent();
+
+        updateProfilePage.update("New first", "New last", "john-doh@localhost", "new");
+
+        String sessionId = events
+                .expectLogin()
+                .event(EventType.UPDATE_PROFILE)
+                .detail(Details.USERNAME, "john-doh@localhost")
+                .user(userId)
+                .session(AssertEvents.isUUID())
+                .removeDetail(Details.CONSENT)
+                .assertEvent()
+                .getSessionId();
+
+        Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        events.expectLogin().detail(Details.USERNAME, "john-doh@localhost").user(userId).session(sessionId).assertEvent();
+
+        // assert user is really updated in persistent store
+        UserRepresentation user = keycloakRule.getUser("test", "new");
+        Assert.assertEquals("New first", user.getFirstName());
+        Assert.assertEquals("New last", user.getLastName());
+        Assert.assertEquals("john-doh@localhost", user.getEmail());
+        Assert.assertEquals("new", user.getUsername());
     }
 
     @Test
@@ -111,7 +144,7 @@ public class RequiredActionUpdateProfileTest {
 
         updateProfilePage.assertCurrent();
 
-        updateProfilePage.update("", "New last", "new@email.com");
+        updateProfilePage.update("", "New last", "new@email.com", "new");
 
         updateProfilePage.assertCurrent();
 
@@ -133,7 +166,7 @@ public class RequiredActionUpdateProfileTest {
 
         updateProfilePage.assertCurrent();
 
-        updateProfilePage.update("New first", "", "new@email.com");
+        updateProfilePage.update("New first", "", "new@email.com", "new");
 
         updateProfilePage.assertCurrent();
 
@@ -155,7 +188,7 @@ public class RequiredActionUpdateProfileTest {
 
         updateProfilePage.assertCurrent();
 
-        updateProfilePage.update("New first", "New last", "");
+        updateProfilePage.update("New first", "New last", "", "new");
 
         updateProfilePage.assertCurrent();
 
@@ -177,7 +210,7 @@ public class RequiredActionUpdateProfileTest {
 
         updateProfilePage.assertCurrent();
 
-        updateProfilePage.update("New first", "New last", "invalidemail");
+        updateProfilePage.update("New first", "New last", "invalidemail", "invalid");
 
         updateProfilePage.assertCurrent();
 
@@ -192,6 +225,52 @@ public class RequiredActionUpdateProfileTest {
     }
 
     @Test
+    public void updateProfileMissingUsername() {
+        loginPage.open();
+
+        loginPage.login("john-doh@localhost", "password");
+
+        updateProfilePage.assertCurrent();
+
+        updateProfilePage.update("New first", "New last", "new@email.com", "");
+
+        updateProfilePage.assertCurrent();
+
+        // assert that form holds submitted values during validation error
+        Assert.assertEquals("New first", updateProfilePage.getFirstName());
+        Assert.assertEquals("New last", updateProfilePage.getLastName());
+        Assert.assertEquals("new@email.com", updateProfilePage.getEmail());
+        Assert.assertEquals("", updateProfilePage.getUsername());
+
+        Assert.assertEquals("Please specify username.", updateProfilePage.getError());
+
+        events.assertEmpty();
+    }
+
+    @Test
+    public void updateProfileDuplicateUsername() {
+        loginPage.open();
+
+        loginPage.login("john-doh@localhost", "password");
+
+        updateProfilePage.assertCurrent();
+
+        updateProfilePage.update("New first", "New last", "new@email.com", "test-user@localhost");
+
+        updateProfilePage.assertCurrent();
+
+        // assert that form holds submitted values during validation error
+        Assert.assertEquals("New first", updateProfilePage.getFirstName());
+        Assert.assertEquals("New last", updateProfilePage.getLastName());
+        Assert.assertEquals("new@email.com", updateProfilePage.getEmail());
+        Assert.assertEquals("test-user@localhost", updateProfilePage.getUsername());
+
+        Assert.assertEquals("Username already exists.", updateProfilePage.getError());
+
+        events.assertEmpty();
+    }
+
+    @Test
     public void updateProfileDuplicatedEmail() {
         loginPage.open();
 
@@ -199,7 +278,7 @@ public class RequiredActionUpdateProfileTest {
 
         updateProfilePage.assertCurrent();
 
-        updateProfilePage.update("New first", "New last", "keycloak-user@localhost");
+        updateProfilePage.update("New first", "New last", "keycloak-user@localhost", "test-user@localhost");
 
         updateProfilePage.assertCurrent();
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
index bae16d5..aaed86e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
@@ -85,7 +85,7 @@ public class AdminAPITest {
             ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
             clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
             UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null);
-            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
+            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, true, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
             return tm.encodeToken(adminRealm, token);
         } finally {
             keycloakRule.stopSession(session, true);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index c30ee36..2097175 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -108,7 +108,7 @@ public class ClientTest extends AbstractClientTest {
         response.close();
         String id = ApiUtil.getCreatedId(response);
 
-        RoleRepresentation role = new RoleRepresentation("test", "test");
+        RoleRepresentation role = new RoleRepresentation("test", "test", false);
         realm.clients().get(id).roles().create(role);
 
         rep = realm.clients().get(id).toRepresentation();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
index 0de7dd6..0f1510b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
@@ -123,7 +123,7 @@ public class ImpersonationTest {
             ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
             clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/" + realm);
             UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null);
-            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
+            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, true, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
             return tm.encodeToken(adminRealm, token);
         } finally {
             keycloakRule.stopSession(session, true);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
index 6cf6427..8208aa2 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
@@ -112,7 +112,7 @@ public class RealmTest extends AbstractClientTest {
     @Test
     // KEYCLOAK-1110
     public void deleteDefaultRole() {
-        RoleRepresentation role = new RoleRepresentation("test", "test");
+        RoleRepresentation role = new RoleRepresentation("test", "test", false);
         realm.roles().create(role);
 
         assertNotNull(realm.roles().get("test").toRepresentation());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
index 88c1ccc..77b6d19 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -30,6 +30,7 @@ import org.keycloak.protocol.oidc.endpoints.AuthorizationEndpoint;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.util.RefreshTokenUtil;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -156,6 +157,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
                 .detail(Details.CODE_ID, codeId)
                 .detail(Details.TOKEN_ID, isUUID())
                 .detail(Details.REFRESH_TOKEN_ID, isUUID())
+                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_REFRESH)
                 .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
                 .session(sessionId);
     }
@@ -164,6 +166,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
         return expect(EventType.REFRESH_TOKEN)
                 .detail(Details.TOKEN_ID, isUUID())
                 .detail(Details.REFRESH_TOKEN_ID, refreshTokenId)
+                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_REFRESH)
                 .detail(Details.UPDATED_REFRESH_TOKEN_ID, isUUID())
                 .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
                 .session(sessionId);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index fb2b5df..d7084c1 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -17,7 +17,6 @@
  */
 package org.keycloak.testsuite.broker;
 
-import org.codehaus.jackson.map.ObjectMapper;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPTestConfiguration.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPTestConfiguration.java
index 31b8d2b..6e433f2 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPTestConfiguration.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPTestConfiguration.java
@@ -20,6 +20,7 @@ public class LDAPTestConfiguration {
     private static final Logger log = Logger.getLogger(LDAPTestConfiguration.class);
 
     private String connectionPropertiesLocation;
+    private int sleepTime;
     private boolean startEmbeddedLdapLerver = true;
     private Map<String, String> config;
 
@@ -109,6 +110,7 @@ public class LDAPTestConfiguration {
         }
 
         startEmbeddedLdapLerver = Boolean.parseBoolean(p.getProperty("idm.test.ldap.start.embedded.ldap.server", "true"));
+        sleepTime = Integer.parseInt(p.getProperty("idm.test.ldap.sleepTime", "1000"));
         log.info("Start embedded server: " + startEmbeddedLdapLerver);
         log.info("Read config: " + config);
     }
@@ -125,4 +127,8 @@ public class LDAPTestConfiguration {
         return startEmbeddedLdapLerver;
     }
 
+    public int getSleepTime() {
+        return sleepTime;
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
index f946825..819ee41 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
@@ -56,7 +56,6 @@ public class SyncProvidersTest {
             Map<String,String> ldapConfig = ldapRule.getConfig();
             ldapConfig.put(LDAPConstants.SYNC_REGISTRATIONS, "false");
             ldapConfig.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
-
             ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap",
                     -1, -1, 0);
 
@@ -91,7 +90,7 @@ public class SyncProvidersTest {
         UsersSyncManager usersSyncManager = new UsersSyncManager();
 
         // wait a bit
-        sleep(1000);
+        sleep(ldapRule.getSleepTime());
 
         KeycloakSession session = keycloakRule.startSession();
         try {
@@ -125,7 +124,7 @@ public class SyncProvidersTest {
             }
 
             // wait a bit
-            sleep(1000);
+            sleep(ldapRule.getSleepTime());
 
             // Add user to LDAP and update 'user5' in LDAP
             LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
@@ -391,9 +390,9 @@ public class SyncProvidersTest {
     }
 
     private void assertSyncEquals(UserFederationSyncResult syncResult, int expectedAdded, int expectedUpdated, int expectedRemoved, int expectedFailed) {
-        Assert.assertEquals(syncResult.getAdded(), expectedAdded);
-        Assert.assertEquals(syncResult.getUpdated(), expectedUpdated);
-        Assert.assertEquals(syncResult.getRemoved(), expectedRemoved);
-        Assert.assertEquals(syncResult.getFailed(), expectedFailed);
+        Assert.assertEquals(expectedAdded, syncResult.getAdded());
+        Assert.assertEquals(expectedUpdated, syncResult.getUpdated());
+        Assert.assertEquals(expectedRemoved, syncResult.getRemoved());
+        Assert.assertEquals(expectedFailed, syncResult.getFailed());
     }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AbstractModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AbstractModelTest.java
index a3e0976..d6d8724 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AbstractModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AbstractModelTest.java
@@ -117,6 +117,7 @@ public class AbstractModelTest {
         Assert.assertEquals(expected.getId(), actual.getId());
         Assert.assertEquals(expected.getName(), actual.getName());
         Assert.assertEquals(expected.getDescription(), actual.getDescription());
+        Assert.assertEquals(expected.isScopeParamRequired(), actual.isScopeParamRequired());
         Assert.assertEquals(expected.getContainer(), actual.getContainer());
         Assert.assertEquals(expected.getComposites().size(), actual.getComposites().size());
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AdapterTest.java
index 48ed318..4e771df 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AdapterTest.java
@@ -68,8 +68,8 @@ public class AdapterTest extends AbstractModelTest {
         Assert.assertEquals(realmModel.getName(), "JUGGLER");
         Assert.assertArrayEquals(realmModel.getPrivateKey().getEncoded(), keyPair.getPrivate().getEncoded());
         Assert.assertArrayEquals(realmModel.getPublicKey().getEncoded(), keyPair.getPublic().getEncoded());
-        Assert.assertEquals(1, realmModel.getDefaultRoles().size());
-        Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
+        Assert.assertEquals(2, realmModel.getDefaultRoles().size());
+        Assert.assertTrue(realmModel.getDefaultRoles().contains("foo"));
     }
 
     @Test
@@ -94,8 +94,8 @@ public class AdapterTest extends AbstractModelTest {
         Assert.assertEquals(realmModel.getName(), "JUGGLER");
         Assert.assertArrayEquals(realmModel.getPrivateKey().getEncoded(), keyPair.getPrivate().getEncoded());
         Assert.assertArrayEquals(realmModel.getPublicKey().getEncoded(), keyPair.getPublic().getEncoded());
-        Assert.assertEquals(1, realmModel.getDefaultRoles().size());
-        Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
+        Assert.assertEquals(2, realmModel.getDefaultRoles().size());
+        Assert.assertTrue(realmModel.getDefaultRoles().contains("foo"));
 
         realmModel.getId();
 
@@ -444,7 +444,7 @@ public class AdapterTest extends AbstractModelTest {
         realmModel.addRole("admin");
         realmModel.addRole("user");
         Set<RoleModel> roles = realmModel.getRoles();
-        Assert.assertEquals(3, roles.size());
+        Assert.assertEquals(4, roles.size());
         UserModel user = realmManager.getSession().users().addUser(realmModel, "bburke");
         RoleModel realmUserRole = realmModel.getRole("user");
         user.grantRole(realmUserRole);
@@ -470,7 +470,7 @@ public class AdapterTest extends AbstractModelTest {
         user.grantRole(application.getRole("user"));
 
         roles = user.getRealmRoleMappings();
-        Assert.assertEquals(roles.size(), 2);
+        Assert.assertEquals(roles.size(), 3);
         assertRolesContains(realmUserRole, roles);
         Assert.assertTrue(user.hasRole(realmUserRole));
         // Role "foo" is default realm role
@@ -485,13 +485,13 @@ public class AdapterTest extends AbstractModelTest {
         // Test that application role 'user' don't clash with realm role 'user'
         Assert.assertNotEquals(realmModel.getRole("user").getId(), application.getRole("user").getId());
 
-        Assert.assertEquals(6, user.getRoleMappings().size());
+        Assert.assertEquals(7, user.getRoleMappings().size());
 
         // Revoke some roles
         user.deleteRoleMapping(realmModel.getRole("foo"));
         user.deleteRoleMapping(appBarRole);
         roles = user.getRoleMappings();
-        Assert.assertEquals(4, roles.size());
+        Assert.assertEquals(5, roles.size());
         assertRolesContains(realmUserRole, roles);
         assertRolesContains(application.getRole("user"), roles);
         Assert.assertFalse(user.hasRole(appBarRole));
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
index 5bc3556..597e7dd 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
@@ -1,6 +1,7 @@
 package org.keycloak.testsuite.model;
 
 import java.util.List;
+import java.util.Set;
 
 import org.junit.Assert;
 import org.junit.ClassRule;
@@ -89,4 +90,51 @@ public class CacheTest {
         }
     }
 
+    // KEYCLOAK-1842
+    @Test
+    public void testRoleMappingsInvalidatedWhenClientRemoved() {
+        KeycloakSession session = kc.startSession();
+        try {
+            RealmModel realm = session.realms().getRealmByName("test");
+            UserModel user = session.users().addUser(realm, "joel");
+            ClientModel client = realm.addClient("foo");
+            RoleModel fooRole = client.addRole("foo-role");
+            user.grantRole(fooRole);
+        } finally {
+            session.getTransaction().commit();
+            session.close();
+        }
+
+        // Remove client
+        session = kc.startSession();
+        int grantedRolesCount;
+        try {
+            RealmModel realm = session.realms().getRealmByName("test");
+            UserModel user = session.users().getUserByUsername("joel", realm);
+            grantedRolesCount = user.getRoleMappings().size();
+
+            ClientModel client = realm.getClientByClientId("foo");
+            realm.removeClient(client.getId());
+        } finally {
+            session.getTransaction().commit();
+            session.close();
+        }
+
+        // Assert role mappings was removed from user as well
+        session = kc.startSession();
+        try {
+            RealmModel realm = session.realms().getRealmByName("test");
+            UserModel user = session.users().getUserByUsername("joel", realm);
+            Set<RoleModel> roles = user.getRoleMappings();
+            for (RoleModel role : roles) {
+                Assert.assertNotNull(role.getContainer());
+            }
+
+            Assert.assertEquals(roles.size(), grantedRolesCount - 1);
+        } finally {
+            session.getTransaction().commit();
+            session.close();
+        }
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
index 2f33e43..6f42fd5 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
@@ -79,7 +79,7 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertEquals(1, creds.size());
         RequiredCredentialModel cred = creds.get(0);
         Assert.assertEquals("password", cred.getFormLabel());
-        Assert.assertEquals(2, realm.getDefaultRoles().size());
+        Assert.assertEquals(3, realm.getDefaultRoles().size());
 
         Assert.assertNotNull(realm.getRole("foo"));
         Assert.assertNotNull(realm.getRole("bar"));
@@ -132,6 +132,10 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertTrue(allRoles.contains(application.getRole("app-admin")));
         Assert.assertTrue(allRoles.contains(otherApp.getRole("otherapp-admin")));
 
+        Assert.assertTrue(application.getRole("app-admin").isScopeParamRequired());
+        Assert.assertFalse(otherApp.getRole("otherapp-admin").isScopeParamRequired());
+        Assert.assertFalse(otherApp.getRole("otherapp-user").isScopeParamRequired());
+
         UserModel wburke =  session.users().getUserByUsername("wburke", realm);
         // user with creation timestamp in import
         Assert.assertEquals(new Long(123654), wburke.getCreatedTimestamp());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
index 258dd3c..f0118c2 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
@@ -4,6 +4,8 @@ import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OfflineClientSessionModel;
+import org.keycloak.models.OfflineUserSessionModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserModel.RequiredAction;
@@ -283,6 +285,59 @@ public class UserModelTest extends AbstractModelTest {
         Assert.assertNull(session.users().getUserByUsername("user1", realm));
     }
 
+    @Test
+    public void testOfflineSessionsRemoved() {
+        RealmModel realm = realmManager.createRealm("original");
+        ClientModel fooClient = realm.addClient("foo");
+        ClientModel barClient = realm.addClient("bar");
+
+        UserModel user1 = session.users().addUser(realm, "user1");
+        addOfflineUserSession(user1, "123", "something1");
+        addOfflineClientSession(user1, "456", "123", fooClient.getId(), "something2");
+        addOfflineClientSession(user1, "789", "123", barClient.getId(), "something3");
+
+        commit();
+
+        realm = realmManager.getRealmByName("original");
+        realm.removeClient(barClient.getId());
+
+        commit();
+
+        realm = realmManager.getRealmByName("original");
+        user1 = session.users().getUserByUsername("user1", realm);
+        Assert.assertEquals("something1", user1.getOfflineUserSession("123").getData());
+        Assert.assertEquals("something2", user1.getOfflineClientSession("456").getData());
+        Assert.assertNull(user1.getOfflineClientSession("789"));
+
+        realm.removeClient(fooClient.getId());
+
+        commit();
+
+        realm = realmManager.getRealmByName("original");
+        user1 = session.users().getUserByUsername("user1", realm);
+        Assert.assertNull(user1.getOfflineClientSession("456"));
+        Assert.assertNull(user1.getOfflineClientSession("789"));
+        Assert.assertNull(user1.getOfflineUserSession("123"));
+        Assert.assertEquals(0, user1.getOfflineUserSessions().size());
+        Assert.assertEquals(0, user1.getOfflineClientSessions().size());
+    }
+
+    private void addOfflineUserSession(UserModel user, String userSessionId, String data) {
+        OfflineUserSessionModel model = new OfflineUserSessionModel();
+        model.setUserSessionId(userSessionId);
+        model.setData(data);
+        user.addOfflineUserSession(model);
+    }
+
+    private void addOfflineClientSession(UserModel user, String clientSessionId, String userSessionId, String clientId, String data) {
+        OfflineClientSessionModel model = new OfflineClientSessionModel();
+        model.setClientSessionId(clientSessionId);
+        model.setUserSessionId(userSessionId);
+        model.setClientId(clientId);
+        model.setData(data);
+        user.addOfflineClientSession(model);
+    }
+
     public static void assertEquals(UserModel expected, UserModel actual) {
         Assert.assertEquals(expected.getUsername(), actual.getUsername());
         Assert.assertEquals(expected.getCreatedTimestamp(), actual.getCreatedTimestamp());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index cbfc76f..24f4911 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -180,7 +180,11 @@ public class AccessTokenTest {
         Assert.assertEquals("invalid_grant", response.getError());
         Assert.assertEquals("Incorrect redirect_uri", response.getErrorDescription());
 
-        events.expectCodeToToken(codeId, loginEvent.getSessionId()).error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).assertEvent();
+        events.expectCodeToToken(codeId, loginEvent.getSessionId()).error("invalid_code")
+                .removeDetail(Details.TOKEN_ID)
+                .removeDetail(Details.REFRESH_TOKEN_ID)
+                .removeDetail(Details.REFRESH_TOKEN_TYPE)
+                .assertEvent();
     }
 
     @Test
@@ -201,7 +205,13 @@ public class AccessTokenTest {
         assertNull(tokenResponse.getAccessToken());
         assertNull(tokenResponse.getRefreshToken());
 
-        events.expectCodeToToken(codeId, sessionId).removeDetail(Details.TOKEN_ID).user((String) null).session((String) null).removeDetail(Details.REFRESH_TOKEN_ID).error(Errors.INVALID_CODE).assertEvent();
+        events.expectCodeToToken(codeId, sessionId)
+                .removeDetail(Details.TOKEN_ID)
+                .user((String) null)
+                .session((String) null)
+                .removeDetail(Details.REFRESH_TOKEN_ID)
+                .removeDetail(Details.REFRESH_TOKEN_TYPE)
+                .error(Errors.INVALID_CODE).assertEvent();
 
         events.clear();
     }
@@ -230,7 +240,11 @@ public class AccessTokenTest {
         Assert.assertEquals(400, response.getStatusCode());
 
         AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
-        expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).user((String) null);
+        expectedEvent.error("invalid_code")
+                .removeDetail(Details.TOKEN_ID)
+                .removeDetail(Details.REFRESH_TOKEN_ID)
+                .removeDetail(Details.REFRESH_TOKEN_TYPE)
+                .user((String) null);
         expectedEvent.assertEvent();
 
         events.clear();
@@ -264,7 +278,11 @@ public class AccessTokenTest {
         Assert.assertEquals(400, response.getStatusCode());
 
         AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
-        expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).user((String) null);
+        expectedEvent.error("invalid_code")
+                .removeDetail(Details.TOKEN_ID)
+                .removeDetail(Details.REFRESH_TOKEN_ID)
+                .removeDetail(Details.REFRESH_TOKEN_TYPE)
+                .user((String) null);
         expectedEvent.assertEvent();
 
         events.clear();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
index 2363305..059cdd7 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
@@ -34,6 +34,7 @@ import org.keycloak.models.ClientModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
@@ -290,4 +291,71 @@ public class OAuthGrantTest {
         });
     }
 
+    @Test
+    public void oauthGrantScopeParamRequired() throws Exception {
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                ClientModel thirdParty = appRealm.getClientByClientId("third-party");
+                RoleModel barAppRole = thirdParty.addRole("bar-role");
+                barAppRole.setScopeParamRequired(true);
+
+                RoleModel fooRole = appRealm.addRole("foo-role");
+                fooRole.setScopeParamRequired(true);
+                thirdParty.addScopeMapping(fooRole);
+
+                UserModel testUser = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm);
+                testUser.grantRole(fooRole);
+                testUser.grantRole(barAppRole);
+            }
+
+        });
+
+        // Assert roles not on grant screen when not requested
+        oauth.clientId("third-party");
+        oauth.doLoginGrant("test-user@localhost", "password");
+        grantPage.assertCurrent();
+        Assert.assertFalse(driver.getPageSource().contains("foo-role"));
+        Assert.assertFalse(driver.getPageSource().contains("bar-role"));
+        grantPage.cancel();
+
+        events.expectLogin()
+                .client("third-party")
+                .error("rejected_by_user")
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
+
+        oauth.scope("foo-role third-party/bar-role");
+        oauth.doLoginGrant("test-user@localhost", "password");
+        grantPage.assertCurrent();
+        Assert.assertTrue(driver.getPageSource().contains("foo-role"));
+        Assert.assertTrue(driver.getPageSource().contains("bar-role"));
+        grantPage.accept();
+
+        events.expectLogin()
+                .client("third-party")
+                .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+                .assertEvent();
+
+        // Revoke
+        accountAppsPage.open();
+        accountAppsPage.revokeGrant("third-party");
+        events.expect(EventType.REVOKE_GRANT)
+                .client("account").detail(Details.REVOKED_CLIENT, "third-party").assertEvent();
+
+        // cleanup
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                appRealm.removeRole(appRealm.getRole("foo-role"));
+                ClientModel thirdparty = appRealm.getClientByClientId("third-party");
+                thirdparty.removeRole(thirdparty.getRole("bar-role"));
+            }
+
+        });
+
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
new file mode 100644
index 0000000..8eab300
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
@@ -0,0 +1,552 @@
+package org.keycloak.testsuite.oauth;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+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 org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
+import org.keycloak.constants.ServiceAccountConstants;
+import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
+import org.keycloak.events.Event;
+import org.keycloak.events.EventType;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.RefreshToken;
+import org.keycloak.services.managers.ClientManager;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.pages.AccountApplicationsPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.OAuthGrantPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.RefreshTokenUtil;
+import org.keycloak.util.Time;
+import org.keycloak.util.UriUtils;
+import org.openqa.selenium.WebDriver;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OfflineTokenTest {
+
+    @ClassRule
+    public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+
+        @Override
+        public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+            // For testing
+            appRealm.setAccessTokenLifespan(10);
+            appRealm.setSsoSessionIdleTimeout(30);
+
+            ClientModel app = new ClientManager(manager).createClient(appRealm, "offline-client");
+            app.setSecret("secret1");
+            String testAppRedirectUri = appRealm.getClientByClientId("test-app").getRedirectUris().iterator().next();
+            offlineClientAppUri = UriUtils.getOrigin(testAppRedirectUri) + "/offline-client";
+            app.setRedirectUris(new HashSet<>(Arrays.asList(offlineClientAppUri)));
+            app.setManagementUrl(offlineClientAppUri);
+
+            new ClientManager(manager).enableServiceAccount(app);
+            UserModel serviceAccountUser = manager.getSession().users().getUserByUsername(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "offline-client", appRealm);
+            RoleModel customerUserRole = appRealm.getClientByClientId("test-app").getRole("customer-user");
+            serviceAccountUser.grantRole(customerUserRole);
+
+            userId = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm).getId();
+
+            URL url = getClass().getResource("/oidc/offline-client-keycloak.json");
+            keycloakRule.createApplicationDeployment()
+                    .name("offline-client").contextPath("/offline-client")
+                    .servletClass(OfflineTokenServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
+        }
+
+    });
+
+    private static String userId;
+    private static String offlineClientAppUri;
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    @WebResource
+    protected WebDriver driver;
+
+    @WebResource
+    protected OAuthClient oauth;
+
+    @WebResource
+    protected LoginPage loginPage;
+
+    @WebResource
+    protected OAuthGrantPage oauthGrantPage;
+
+    @WebResource
+    protected AccountApplicationsPage accountAppPage;
+
+    @Rule
+    public AssertEvents events = new AssertEvents(keycloakRule);
+
+
+//    @Test
+//    public void testSleep() throws Exception {
+//        Thread.sleep(9999000);
+//    }
+
+    @Test
+    public void offlineTokenDisabledForClient() throws Exception {
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                appRealm.getClientByClientId("offline-client").setFullScopeAllowed(false);
+            }
+
+        });
+
+        oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
+        oauth.clientId("offline-client");
+        oauth.redirectUri(offlineClientAppUri);
+        oauth.doLogin("test-user@localhost", "password");
+
+        Event loginEvent = events.expectLogin()
+                .client("offline-client")
+                .detail(Details.REDIRECT_URI, offlineClientAppUri)
+                .assertEvent();
+
+        String sessionId = loginEvent.getSessionId();
+        String codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "secret1");
+
+        assertEquals(400, tokenResponse.getStatusCode());
+        assertEquals("not_allowed", tokenResponse.getError());
+
+        events.expectCodeToToken(codeId, sessionId)
+                .client("offline-client")
+                .error("not_allowed")
+                .clearDetails()
+                .assertEvent();
+
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                appRealm.getClientByClientId("offline-client").setFullScopeAllowed(true);
+            }
+
+        });
+    }
+
+    @Test
+    public void offlineTokenUserNotAllowed() throws Exception {
+        String userId = keycloakRule.getUser("test", "keycloak-user@localhost").getId();
+
+        oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
+        oauth.clientId("offline-client");
+        oauth.redirectUri(offlineClientAppUri);
+        oauth.doLogin("keycloak-user@localhost", "password");
+
+        Event loginEvent = events.expectLogin()
+                .client("offline-client")
+                .user(userId)
+                .detail(Details.REDIRECT_URI, offlineClientAppUri)
+                .assertEvent();
+
+        String sessionId = loginEvent.getSessionId();
+        String codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "secret1");
+
+        assertEquals(400, tokenResponse.getStatusCode());
+        assertEquals("not_allowed", tokenResponse.getError());
+
+        events.expectCodeToToken(codeId, sessionId)
+                .client("offline-client")
+                .user(userId)
+                .error("not_allowed")
+                .clearDetails()
+                .assertEvent();
+    }
+
+    @Test
+    public void offlineTokenBrowserFlow() throws Exception {
+        oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
+        oauth.clientId("offline-client");
+        oauth.redirectUri(offlineClientAppUri);
+        oauth.doLogin("test-user@localhost", "password");
+
+        Event loginEvent = events.expectLogin()
+                .client("offline-client")
+                .detail(Details.REDIRECT_URI, offlineClientAppUri)
+                .assertEvent();
+
+        final String sessionId = loginEvent.getSessionId();
+        String codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "secret1");
+        AccessToken token = oauth.verifyToken(tokenResponse.getAccessToken());
+        String offlineTokenString = tokenResponse.getRefreshToken();
+        RefreshToken offlineToken = oauth.verifyRefreshToken(offlineTokenString);
+
+        events.expectCodeToToken(codeId, sessionId)
+                .client("offline-client")
+                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .assertEvent();
+
+        Assert.assertEquals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
+        Assert.assertEquals(0, offlineToken.getExpiration());
+
+        testRefreshWithOfflineToken(token, offlineToken, offlineTokenString, sessionId, userId);
+    }
+
+    private void testRefreshWithOfflineToken(AccessToken oldToken, RefreshToken offlineToken, String offlineTokenString,
+                                             final String sessionId, String userId) {
+        // Change offset to big value to ensure userSession expired
+        Time.setOffset(99999);
+        Assert.assertFalse(oldToken.isActive());
+        Assert.assertTrue(offlineToken.isActive());
+
+        // Assert userSession expired
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                manager.getSession().sessions().removeExpiredUserSessions(appRealm);
+            }
+
+        });
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                Assert.assertNull(manager.getSession().sessions().getUserSession(appRealm, sessionId));
+            }
+
+        });
+
+
+        OAuthClient.AccessTokenResponse response = oauth.doRefreshTokenRequest(offlineTokenString, "secret1");
+        AccessToken refreshedToken = oauth.verifyToken(response.getAccessToken());
+        Assert.assertEquals(200, response.getStatusCode());
+        Assert.assertEquals(sessionId, refreshedToken.getSessionState());
+
+        // Assert no refreshToken in the response
+        Assert.assertNull(response.getRefreshToken());
+        Assert.assertNotEquals(oldToken.getId(), refreshedToken.getId());
+
+        Assert.assertEquals(userId, refreshedToken.getSubject());
+
+        Assert.assertEquals(2, refreshedToken.getRealmAccess().getRoles().size());
+        Assert.assertTrue(refreshedToken.getRealmAccess().isUserInRole("user"));
+        Assert.assertTrue(refreshedToken.getRealmAccess().isUserInRole(Constants.OFFLINE_ACCESS_ROLE));
+
+        Assert.assertEquals(1, refreshedToken.getResourceAccess("test-app").getRoles().size());
+        Assert.assertTrue(refreshedToken.getResourceAccess("test-app").isUserInRole("customer-user"));
+
+        Event refreshEvent = events.expectRefresh(offlineToken.getId(), sessionId)
+                .client("offline-client")
+                .user(userId)
+                .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID)
+                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .assertEvent();
+        Assert.assertNotEquals(oldToken.getId(), refreshEvent.getDetails().get(Details.TOKEN_ID));
+
+        Time.setOffset(0);
+    }
+
+    @Test
+    public void offlineTokenDirectGrantFlow() throws Exception {
+        oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
+        oauth.clientId("offline-client");
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest("secret1", "test-user@localhost", "password");
+
+        AccessToken token = oauth.verifyToken(tokenResponse.getAccessToken());
+        String offlineTokenString = tokenResponse.getRefreshToken();
+        RefreshToken offlineToken = oauth.verifyRefreshToken(offlineTokenString);
+
+        events.expectLogin()
+                .client("offline-client")
+                .user(userId)
+                .session(token.getSessionState())
+                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.TOKEN_ID, token.getId())
+                .detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
+                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.USERNAME, "test-user@localhost")
+                .removeDetail(Details.CODE_ID)
+                .removeDetail(Details.REDIRECT_URI)
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
+
+        Assert.assertEquals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
+        Assert.assertEquals(0, offlineToken.getExpiration());
+
+        testRefreshWithOfflineToken(token, offlineToken, offlineTokenString, token.getSessionState(), userId);
+    }
+
+    @Test
+    public void offlineTokenServiceAccountFlow() throws Exception {
+        oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
+        oauth.clientId("offline-client");
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.doClientCredentialsGrantAccessTokenRequest("secret1");
+
+        AccessToken token = oauth.verifyToken(tokenResponse.getAccessToken());
+        String offlineTokenString = tokenResponse.getRefreshToken();
+        RefreshToken offlineToken = oauth.verifyRefreshToken(offlineTokenString);
+
+        String serviceAccountUserId = keycloakRule.getUser("test",  ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "offline-client").getId();
+
+        events.expectClientLogin()
+                .client("offline-client")
+                .user(serviceAccountUserId)
+                .session(token.getSessionState())
+                .detail(Details.TOKEN_ID, token.getId())
+                .detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
+                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "offline-client")
+                .assertEvent();
+
+        Assert.assertEquals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
+        Assert.assertEquals(0, offlineToken.getExpiration());
+
+        testRefreshWithOfflineToken(token, offlineToken, offlineTokenString, token.getSessionState(), serviceAccountUserId);
+
+
+        // Now retrieve another offline token and verify that previous offline token is not valid anymore
+        tokenResponse = oauth.doClientCredentialsGrantAccessTokenRequest("secret1");
+
+        AccessToken token2 = oauth.verifyToken(tokenResponse.getAccessToken());
+        String offlineTokenString2 = tokenResponse.getRefreshToken();
+        RefreshToken offlineToken2 = oauth.verifyRefreshToken(offlineTokenString2);
+
+        events.expectClientLogin()
+                .client("offline-client")
+                .user(serviceAccountUserId)
+                .session(token2.getSessionState())
+                .detail(Details.TOKEN_ID, token2.getId())
+                .detail(Details.REFRESH_TOKEN_ID, offlineToken2.getId())
+                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "offline-client")
+                .assertEvent();
+
+        // Refresh with old offline token should fail
+        OAuthClient.AccessTokenResponse response = oauth.doRefreshTokenRequest(offlineTokenString, "secret1");
+        Assert.assertEquals(400, response.getStatusCode());
+        Assert.assertEquals("invalid_grant", response.getError());
+
+        events.expectRefresh(offlineToken.getId(), offlineToken.getSessionState())
+                .error(Errors.INVALID_TOKEN)
+                .client("offline-client")
+                .user(serviceAccountUserId)
+                .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID)
+                .removeDetail(Details.TOKEN_ID)
+                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .assertEvent();
+
+        // Refresh with new offline token is ok
+        testRefreshWithOfflineToken(token2, offlineToken2, offlineTokenString2, token2.getSessionState(), serviceAccountUserId);
+    }
+
+    @Test
+    public void testServlet() {
+        OfflineTokenServlet.tokenInfo = null;
+
+        String servletUri = UriBuilder.fromUri(offlineClientAppUri)
+                .queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
+                .build().toString();
+        driver.navigate().to(servletUri);
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith(offlineClientAppUri));
+
+        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getExpiration(), 0);
+
+        String accessTokenId = OfflineTokenServlet.tokenInfo.accessToken.getId();
+        String refreshTokenId = OfflineTokenServlet.tokenInfo.refreshToken.getId();
+
+        // Assert access token will be refreshed, but offline token will be still the same
+        Time.setOffset(9999);
+        driver.navigate().to(offlineClientAppUri);
+        Assert.assertTrue(driver.getCurrentUrl().startsWith(offlineClientAppUri));
+        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getId(), refreshTokenId);
+        Assert.assertNotEquals(OfflineTokenServlet.tokenInfo.accessToken.getId(), accessTokenId);
+
+        // Ensure that logout works for webapp (even if offline token will be still valid in Keycloak DB)
+        driver.navigate().to(offlineClientAppUri + "/logout");
+        loginPage.assertCurrent();
+        driver.navigate().to(offlineClientAppUri);
+        loginPage.assertCurrent();
+
+        Time.setOffset(0);
+        events.clear();
+    }
+
+    @Test
+    public void testServletWithRevoke() {
+        // Login to servlet first with offline token
+        String servletUri = UriBuilder.fromUri(offlineClientAppUri)
+                .queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
+                .build().toString();
+        driver.navigate().to(servletUri);
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith(offlineClientAppUri));
+
+        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+
+        // Assert refresh works with increased time
+        Time.setOffset(9999);
+        driver.navigate().to(offlineClientAppUri);
+        Assert.assertTrue(driver.getCurrentUrl().startsWith(offlineClientAppUri));
+        Time.setOffset(0);
+
+        events.clear();
+
+        // Go to account service and revoke grant
+        accountAppPage.open();
+        List<String> additionalGrants = accountAppPage.getApplications().get("offline-client").getAdditionalGrants();
+        Assert.assertEquals(additionalGrants.size(), 1);
+        Assert.assertEquals(additionalGrants.get(0), "Offline Token");
+        accountAppPage.revokeGrant("offline-client");
+        Assert.assertEquals(accountAppPage.getApplications().get("offline-client").getAdditionalGrants().size(), 0);
+
+        events.expect(EventType.REVOKE_GRANT)
+                .client("account").detail(Details.REVOKED_CLIENT, "offline-client").assertEvent();
+
+        // Assert refresh doesn't work now (increase time one more time)
+        Time.setOffset(9999);
+        driver.navigate().to(offlineClientAppUri);
+        Assert.assertFalse(driver.getCurrentUrl().startsWith(offlineClientAppUri));
+        loginPage.assertCurrent();
+        Time.setOffset(0);
+    }
+
+    @Test
+    public void testServletWithConsent() {
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                appRealm.getClientByClientId("offline-client").setConsentRequired(true);
+            }
+
+        });
+
+        // Assert grant page doesn't have 'Offline Access' role when offline token is not requested
+        driver.navigate().to(offlineClientAppUri);
+        loginPage.login("test-user@localhost", "password");
+        oauthGrantPage.assertCurrent();
+        Assert.assertFalse(driver.getPageSource().contains("Offline access"));
+        oauthGrantPage.cancel();
+
+        // Assert grant page has 'Offline Access' role now
+        String servletUri = UriBuilder.fromUri(offlineClientAppUri)
+                .queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
+                .build().toString();
+        driver.navigate().to(servletUri);
+        loginPage.login("test-user@localhost", "password");
+        oauthGrantPage.assertCurrent();
+        Assert.assertTrue(driver.getPageSource().contains("Offline access"));
+        oauthGrantPage.accept();
+
+        Assert.assertTrue(driver.getCurrentUrl().startsWith(offlineClientAppUri));
+        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+
+        accountAppPage.open();
+        AccountApplicationsPage.AppEntry offlineClient = accountAppPage.getApplications().get("offline-client");
+        Assert.assertTrue(offlineClient.getRolesGranted().contains("Offline access"));
+        Assert.assertTrue(offlineClient.getAdditionalGrants().contains("Offline Token"));
+
+        events.clear();
+
+        // Revert change
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                appRealm.getClientByClientId("offline-client").setConsentRequired(false);
+            }
+
+        });
+    }
+
+    public static class OfflineTokenServlet extends HttpServlet {
+
+        private static TokenInfo tokenInfo;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+            if (req.getRequestURI().endsWith("logout")) {
+
+                UriBuilder redirectUriBuilder = UriBuilder.fromUri(offlineClientAppUri);
+                if (req.getParameter(OAuth2Constants.SCOPE) != null) {
+                    redirectUriBuilder.queryParam(OAuth2Constants.SCOPE, req.getParameter(OAuth2Constants.SCOPE));
+                }
+                String redirectUri = redirectUriBuilder.build().toString();
+
+                String origin = UriUtils.getOrigin(req.getRequestURL().toString());
+                String serverLogoutRedirect = UriBuilder.fromUri(origin + "/auth/realms/test/protocol/openid-connect/logout")
+                        .queryParam("redirect_uri", redirectUri)
+                        .build().toString();
+
+                resp.sendRedirect(serverLogoutRedirect);
+                return;
+            }
+
+            StringBuilder response = new StringBuilder("<html><head><title>Offline token servlet</title></head><body><pre>");
+            RefreshableKeycloakSecurityContext ctx = (RefreshableKeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+            String accessTokenPretty = JsonSerialization.writeValueAsPrettyString(ctx.getToken());
+            RefreshToken refreshToken = new JWSInput(ctx.getRefreshToken()).readJsonContent(RefreshToken.class);
+            String refreshTokenPretty = JsonSerialization.writeValueAsPrettyString(refreshToken);
+
+            response = response.append(accessTokenPretty)
+                    .append(refreshTokenPretty)
+                    .append("</pre></body></html>");
+            resp.getWriter().println(response.toString());
+
+            tokenInfo = new TokenInfo(ctx.getToken(), refreshToken);
+        }
+
+    }
+
+    private static class TokenInfo {
+
+        private final AccessToken accessToken;
+        private final RefreshToken refreshToken;
+
+        public TokenInfo(AccessToken accessToken, RefreshToken refreshToken) {
+            this.accessToken = accessToken;
+            this.refreshToken = refreshToken;
+        }
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
index b06e433..087f82f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -76,6 +76,8 @@ public class OAuthClient {
 
     private String state = "mystate";
 
+    private String scope;
+
     private String uiLocales = null;
 
     private PublicKey realmPublicKey;
@@ -192,6 +194,9 @@ public class OAuthClient {
             if (clientSessionHost != null) {
                 parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
             }
+            if (scope != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.SCOPE, scope));
+            }
 
             UrlEncodedFormEntity formEntity;
             try {
@@ -218,6 +223,10 @@ public class OAuthClient {
             List<NameValuePair> parameters = new LinkedList<NameValuePair>();
             parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
 
+            if (scope != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.SCOPE, scope));
+            }
+
             UrlEncodedFormEntity formEntity;
             try {
                 formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
@@ -390,6 +399,9 @@ public class OAuthClient {
         if(uiLocales != null){
             b.queryParam(LocaleHelper.UI_LOCALES_PARAM, uiLocales);
         }
+        if (scope != null) {
+            b.queryParam(OAuth2Constants.SCOPE, scope);
+        }
         return b.build(realm).toString();
     }
 
@@ -452,6 +464,11 @@ public class OAuthClient {
         return this;
     }
 
+    public OAuthClient scope(String scope) {
+        this.scope = scope;
+        return this;
+    }
+
     public OAuthClient uiLocales(String uiLocales){
         this.uiLocales = uiLocales;
         return this;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountApplicationsPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountApplicationsPage.java
index f88db27..b48559c 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountApplicationsPage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountApplicationsPage.java
@@ -77,6 +77,15 @@ public class AccountApplicationsPage extends AbstractAccountPage {
                             currentEntry.addMapper(protMapper);
                         }
                         break;
+                    case 5:
+                        String additionalGrant = col.getText();
+                        if (additionalGrant.isEmpty()) break;
+                        String[] grants = additionalGrant.split(",");
+                        for (String grant : grants) {
+                            grant = grant.trim();
+                            currentEntry.addAdditionalGrant(grant);
+                        }
+                        break;
                 }
             }
         }
@@ -89,6 +98,7 @@ public class AccountApplicationsPage extends AbstractAccountPage {
         private final List<String> rolesAvailable = new ArrayList<String>();
         private final List<String> rolesGranted = new ArrayList<String>();
         private final List<String> protocolMappersGranted = new ArrayList<String>();
+        private final List<String> additionalGrants = new ArrayList<>();
 
         private void addAvailableRole(String role) {
             rolesAvailable.add(role);
@@ -102,6 +112,10 @@ public class AccountApplicationsPage extends AbstractAccountPage {
             protocolMappersGranted.add(protocolMapper);
         }
 
+        private void addAdditionalGrant(String grant) {
+            additionalGrants.add(grant);
+        }
+
         public List<String> getRolesGranted() {
             return rolesGranted;
         }
@@ -113,5 +127,9 @@ public class AccountApplicationsPage extends AbstractAccountPage {
         public List<String> getProtocolMappersGranted() {
             return protocolMappersGranted;
         }
+
+        public List<String> getAdditionalGrants() {
+            return additionalGrants;
+        }
     }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginUpdateProfileEditUsernameAllowedPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginUpdateProfileEditUsernameAllowedPage.java
new file mode 100644
index 0000000..bba3f93
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginUpdateProfileEditUsernameAllowedPage.java
@@ -0,0 +1,51 @@
+/*
+ * 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.pages;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+public class LoginUpdateProfileEditUsernameAllowedPage extends LoginUpdateProfilePage {
+
+    @FindBy(id = "username")
+    private WebElement usernameInput;
+
+    public void update(String firstName, String lastName, String email, String username) {
+        usernameInput.clear();
+        usernameInput.sendKeys(username);
+        update(firstName, lastName, email);
+    }
+
+    public String getUsername() {
+        return usernameInput.getAttribute("value");
+    }
+
+    public boolean isCurrent() {
+        return driver.getTitle().equals("Update Account Information");
+    }
+
+    @Override
+    public void open() {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java
index add9708..438938f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java
@@ -57,4 +57,8 @@ public class LDAPRule extends ExternalResource {
     public Map<String, String> getConfig() {
         return ldapTestConfiguration.getLDAPConfig();
     }
+
+    public int getSleepTime() {
+        return ldapTestConfiguration.getSleepTime();
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
index d556a83..2d2ab44 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
@@ -457,7 +457,7 @@ public class SamlBindingTest {
             ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
             clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
             UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null);
-            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
+            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, true, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
             return tm.encodeToken(adminRealm, token);
         } finally {
             keycloakRule.stopSession(session, true);
diff --git a/testsuite/integration/src/test/resources/model/testrealm.json b/testsuite/integration/src/test/resources/model/testrealm.json
index acbbdf5..f7c8cdd 100755
--- a/testsuite/integration/src/test/resources/model/testrealm.json
+++ b/testsuite/integration/src/test/resources/model/testrealm.json
@@ -198,7 +198,8 @@
         "application" : {
             "Application" : [
                 {
-                    "name": "app-admin"
+                    "name": "app-admin",
+                    "scopeParamRequired": true
                 },
                 {
                     "name": "app-user"
@@ -206,7 +207,8 @@
             ],
             "OtherApp" : [
                 {
-                    "name": "otherapp-admin"
+                    "name": "otherapp-admin",
+                    "scopeParamRequired": false
                 },
                 {
                     "name": "otherapp-user"
diff --git a/testsuite/integration/src/test/resources/oidc/offline-client-keycloak.json b/testsuite/integration/src/test/resources/oidc/offline-client-keycloak.json
new file mode 100644
index 0000000..bc7be17
--- /dev/null
+++ b/testsuite/integration/src/test/resources/oidc/offline-client-keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm": "test",
+  "resource": "offline-client",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "credentials": {
+    "secret": "secret1"
+  }
+}
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/testrealm.json b/testsuite/integration/src/test/resources/testrealm.json
index 8ad29cc..e16e3e2 100755
--- a/testsuite/integration/src/test/resources/testrealm.json
+++ b/testsuite/integration/src/test/resources/testrealm.json
@@ -5,6 +5,7 @@
     "sslRequired": "external",
     "registrationAllowed": true,
     "resetPasswordAllowed": true,
+    "editUsernameAllowed" : true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
@@ -25,6 +26,22 @@
                 { "type" : "password",
                   "value" : "password" }
             ],
+            "realmRoles": ["user", "offline_access"],
+            "clientRoles": {
+                "test-app": [ "customer-user" ],
+                "account": [ "view-profile", "manage-account" ]
+            }
+        },
+        {
+            "username" : "john-doh@localhost",
+            "enabled": true,
+            "email" : "john-doh@localhost",
+            "firstName": "John",
+            "lastName": "Doh",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
             "realmRoles": ["user"],
             "clientRoles": {
                 "test-app": [ "customer-user" ],
@@ -32,7 +49,7 @@
             }
         },
         {
-            "username" : "keycloak-user@localhost",
+                "username" : "keycloak-user@localhost",
             "enabled": true,
             "email" : "keycloak-user@localhost",
             "credentials" : [
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..724928a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Account.java
@@ -0,0 +1,81 @@
+/*
+ * 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 setUsername(String value) {
+        username.clear();
+        username.sendKeys(value);
+        return this;
+    }
+    
+    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/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..3c3da23
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginActions.java
@@ -0,0 +1,68 @@
+/*
+ * 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.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;
+    
+    @FindBy(xpath = "//div[@id='kc-error-message']/p")
+    private WebElement error;
+
+    public String getErrorMessage() {
+        waitGuiForElementPresent(error, "Error message should be visible");
+        return error.getText();
+    }
+    
+    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..8329abc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java
@@ -0,0 +1,125 @@
+/*
+ * 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.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.*;
+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;
+    @FindBy(id = "rememberMe")
+    private WebElement rememberMe;
+
+    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();
+    }
+    
+    public void rememberMe(boolean value) {
+        waitForRememberMePresent();
+        boolean selected = rememberMe.isSelected();
+        if ((value && !selected) || !value && selected) {
+            rememberMe.click();
+        }
+    }
+
+//    @Override
+//    public void cancel() {
+//        waitAjaxForElement(cancelButton);
+//        cancelButton.click();
+//    }
+    
+    public void waitForUsernameInputPresent() {
+        accountFields.waitForUsernameInputPresent();
+    }
+
+    public void waitForRegisterLinkNotPresent() {
+        waitAjaxForElementNotPresent(registerLink);
+    }
+
+    public void waitForResetPasswordLinkNotPresent() {
+        waitAjaxForElementNotPresent(forgottenPassword);
+    }
+
+    public void waitForRememberMePresent() {
+        waitAjaxForElement(rememberMe);
+    }
+
+    public void waitForRememberMeNotPresent() {
+        waitAjaxForElementNotPresent(rememberMe);
+    }
+    
+    public void waitForLoginButtonPresent() {
+        waitGuiForElement(loginButton);
+    }
+
+}
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..c9f901d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Registration.java
@@ -0,0 +1,78 @@
+/*
+ * 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 javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.representations.idm.UserRepresentation;
+
+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();
+    }
+    
+    public void waitForConfirmPasswordInputPresent() {
+        passwordFields.waitForConfirmPasswordInputPresent();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/ResetCredentials.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/ResetCredentials.java
new file mode 100644
index 0000000..3b4c4e8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/ResetCredentials.java
@@ -0,0 +1,63 @@
+/*
+ * 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.account.AccountFields;
+import org.keycloak.testsuite.auth.page.account.PasswordFields;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+
+/**
+ *
+ * @author vramik
+ */
+public class ResetCredentials extends LoginActions {
+
+    @Override
+    public UriBuilder createUriBuilder() {
+        return super.createUriBuilder().path("reset-credentials");
+    }
+
+    @Page
+    private AccountFields accountFields;
+    @Page
+    private PasswordFields passwordFields;
+
+    @FindBy(id = "kc-info")
+    private WebElement info;
+    
+    public void resetCredentials(String value) {
+        accountFields.setUsername(value);
+        submit();
+    }
+    
+    public void updatePassword(String password) {
+        passwordFields.setNewPassword(password);
+        passwordFields.setConfirmPassword(password);
+        submit();
+    }
+
+    public String getInfoMessage() {
+        waitGuiForElementPresent(info, "Info message should be visible");
+        return info.getText();
+    }
+}
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/LoginSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/LoginSettings.java
new file mode 100644
index 0000000..2cfcace
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/LoginSettings.java
@@ -0,0 +1,121 @@
+/*
+ * 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 org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author Petr Mensik
+ */
+public class LoginSettings extends RealmSettings {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/login-settings";
+    }
+
+    @Page
+    private LoginSettingsForm form;
+    
+    public LoginSettingsForm form() {
+        return form;
+    }
+    
+    public enum RequireSSLOption {
+        all, external, none;
+    }
+
+    public class LoginSettingsForm extends Form {
+
+        @FindByJQuery("div[class='onoffswitch']:eq(0)")
+        private OnOffSwitch registrationAllowed;
+
+        @FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='registrationEmailAsUsername']]")
+        private OnOffSwitch emailAsUsernameOnOffSwitch;
+
+        @FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='editUsernameAllowed']]")
+        private OnOffSwitch editUsernameAllowed;
+        
+        @FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='resetPasswordAllowed']]")
+        private OnOffSwitch resetPasswordAllowed;
+        
+        @FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='rememberMe']]")
+        private OnOffSwitch rememberMeEnabled;
+
+        @FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='verifyEmail']]")
+        private OnOffSwitch verifyEmailEnabled;
+
+        @FindBy(id = "sslRequired")
+        private Select requireSsl;
+
+        public boolean isRegistrationAllowed() {
+            return registrationAllowed.isOn();
+        }
+        
+        public void setRegistrationAllowed(boolean allowed) {
+            registrationAllowed.setOn(allowed);
+        }
+        
+        public void setEmailAsUsername(boolean emailAsUsername) {
+            emailAsUsernameOnOffSwitch.setOn(emailAsUsername);
+        }
+        
+        public boolean isEditUsernameAllowed() {
+            return editUsernameAllowed.isOn();
+        }
+        
+        public void setEditUsernameAllowed(boolean allowed) {
+            editUsernameAllowed.setOn(allowed);
+        }
+        
+        public boolean isResetPasswordAllowed() {
+            return resetPasswordAllowed.isOn();
+        }
+        
+        public void setResetPasswordAllowed(boolean allowed) {
+            resetPasswordAllowed.setOn(allowed);
+        }
+        
+        public boolean isRememberMeAllowed() {
+            return rememberMeEnabled.isOn();
+        }
+        
+        public void setRememberMeAllowed(boolean allowed) {
+            rememberMeEnabled.setOn(allowed);
+        }
+        
+        public void setVerifyEmailAllowed(boolean allowed) {
+            verifyEmailEnabled.setOn(allowed);
+        }
+        
+        public boolean isVerifyEmailAllowed() {
+            return verifyEmailEnabled.isOn();
+        }
+        
+        public void selectRequireSSL(RequireSSLOption option) {
+            requireSsl.selectByValue(option.name());
+        }
+    }
+
+}
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..b4f974a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleForm.java
@@ -0,0 +1,114 @@
+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[@class='onoffswitch' and ./input[@id='scopeParamRequired']]")
+    private OnOffSwitch scopeParamRequired;
+
+    @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(), isScopeParamRequired());
+        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.setScopeParamRequired(isScopeParamRequired());
+        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());
+        setScopeParamRequired(role.isScopeParamRequired());
+        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 setScopeParamRequired(boolean scopeParamRequired) {
+        this.scopeParamRequired.setOn(scopeParamRequired);
+    }
+
+    public boolean isScopeParamRequired() {
+        return scopeParamRequired.isOn();
+    }
+
+    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..a8a4c35
--- /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", "", false);
+
+        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..13edb9d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java
@@ -0,0 +1,266 @@
+/*
+ * 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 java.util.HashSet;
+import java.util.Set;
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Assert;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.junit.Test;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.account.Account;
+import org.keycloak.testsuite.console.page.realm.LoginSettings;
+import org.keycloak.testsuite.auth.page.login.Registration;
+import org.keycloak.testsuite.auth.page.login.ResetCredentials;
+import org.keycloak.testsuite.auth.page.login.VerifyEmail;
+import org.keycloak.testsuite.console.page.realm.LoginSettings.RequireSSLOption;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import org.openqa.selenium.Cookie;
+
+/**
+ *
+ * @author tkyjovsk
+ * @author vramik
+ */
+public class LoginSettingsTest extends AbstractRealmTest {
+
+    private static final String NEW_USERNAME = "newUsername";
+    
+    @Page
+    private LoginSettings loginSettingsPage;
+    @Page
+    private Registration testRealmRegistrationPage;
+    @Page
+    private ResetCredentials testRealmForgottenPasswordPage;
+    @Page
+    private VerifyEmail testRealmVerifyEmailPage;
+    @Page
+    private Account testAccountPage;
+    
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmRegistrationPage.setAuthRealm(TEST);
+        testRealmForgottenPasswordPage.setAuthRealm(TEST);
+        testRealmVerifyEmailPage.setAuthRealm(TEST);
+        testAccountPage.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.waitForConfirmPasswordInputPresent();
+        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.waitForConfirmPasswordInputPresent();
+        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");
+    }
+    
+    @Test
+    public void editUsername() {
+        log.info("enabling edit username");
+        loginSettingsPage.form().setEditUsernameAllowed(true);
+        loginSettingsPage.form().save();
+        log.debug("enabled");
+        
+        log.info("edit username");
+        testAccountPage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+        testAccountPage.waitForAccountLinkPresent();
+        testAccountPage.setUsername(NEW_USERNAME);
+        testAccountPage.save();
+        testAccountPage.signOut();
+        log.debug("edited");
+        
+        log.info("log in with edited username");
+        testRealmLoginPage.form().login(NEW_USERNAME, PASSWORD);
+        testAccountPage.waitForAccountLinkPresent();
+        log.debug("user is logged in with edited username");
+        
+        log.info("disabling edit username");
+        loginSettingsPage.navigateTo();
+        loginSettingsPage.form().setEditUsernameAllowed(false);
+        loginSettingsPage.form().save();
+        log.debug("disabled");
+        
+        
+    }
+    
+    @Test
+    public void resetPassword() {
+        
+        log.info("enabling reset password");
+        loginSettingsPage.form().setResetPasswordAllowed(true);
+        loginSettingsPage.form().save();
+        log.debug("enabled");
+        
+        testRealmAdminConsolePage.navigateTo();
+        testRealmLoginPage.form().forgotPassword();
+        
+        Assert.assertEquals("Enter your username or email address and we will send you instructions on how to create a new password.", 
+                testRealmForgottenPasswordPage.getInfoMessage());
+        log.info("verified reset password is enabled");
+        
+        log.info("disabling reset password");
+        loginSettingsPage.navigateTo();
+        loginSettingsPage.form().setResetPasswordAllowed(false);
+        loginSettingsPage.form().save();
+        assertFalse(loginSettingsPage.form().isResetPasswordAllowed());
+        log.debug("disabled");
+        
+        testRealmAdminConsolePage.navigateTo();
+        testRealmLoginPage.form().waitForResetPasswordLinkNotPresent();
+        log.info("verified reset password is disabled");
+    }
+    
+    @Test
+    public void rememberMe() {
+        
+        log.info("enabling remember me");
+        loginSettingsPage.form().setRememberMeAllowed(true);
+        loginSettingsPage.form().save();
+        log.debug("enabled");
+        
+        log.info("login with remember me checked");
+        testAccountPage.navigateTo();
+        testRealmLoginPage.form().rememberMe(true);
+        testRealmLoginPage.form().login(testUser);
+        
+        assertTrue("Cookie KEYCLOAK_REMEMBER_ME should be present.", getCookieNames().contains("KEYCLOAK_REMEMBER_ME"));
+        
+        log.info("verified remember me is enabled");
+        
+        log.info("disabling remember me");
+        loginSettingsPage.navigateTo();
+        loginSettingsPage.form().setRememberMeAllowed(false);
+        loginSettingsPage.form().save();
+        assertFalse(loginSettingsPage.form().isRememberMeAllowed());
+        log.debug("disabled");
+        
+        testAccountPage.navigateTo();
+        testAccountPage.signOut();
+        testRealmLoginPage.form().waitForLoginButtonPresent();
+        testRealmLoginPage.form().waitForRememberMeNotPresent();
+        log.info("verified remember me is disabled");
+        
+    }
+    
+    @Test 
+    public void verifyEmail() {
+
+        log.info("enabling verify email");
+        loginSettingsPage.form().setVerifyEmailAllowed(true);
+        loginSettingsPage.form().save();
+        log.debug("enabled");
+        
+        testAccountPage.navigateTo();
+        testRealmLoginPage.form().login(testUser);
+        Assert.assertEquals("Failed to send email, please try again later.", 
+                testRealmVerifyEmailPage.getErrorMessage());
+        
+        log.info("verified verify email is enabled");
+        
+        log.info("disabling verify email");
+        loginSettingsPage.navigateTo();
+        loginSettingsPage.form().setVerifyEmailAllowed(false);
+        loginSettingsPage.form().save();
+        assertFalse(loginSettingsPage.form().isVerifyEmailAllowed());
+        log.debug("disabled");
+        
+        log.debug("create new test user");
+        UserRepresentation newUser = createUserRepresentation("new_user", "new_user@email.test", "new", "user", true);
+        setPasswordFor(newUser, PASSWORD);
+        String id = createUserAndResetPasswordWithAdminClient(testRealmResource(), newUser, PASSWORD);
+        newUser.setId(id);
+        
+        log.info("log in as new user");
+        testAccountPage.navigateTo();        
+        testRealmLoginPage.form().login(newUser);
+        testAccountPage.waitForAccountLinkPresent();
+                
+        log.info("verified verify email is disabled");
+    }
+    
+    @Test
+    public void requireSSLAllRequests() throws InterruptedException {
+        log.info("set require ssl for all requests");
+        loginSettingsPage.form().selectRequireSSL(RequireSSLOption.all);
+        loginSettingsPage.form().save();
+        log.debug("set");
+        
+        log.info("check HTTPS required");
+        testAccountPage.navigateTo();
+        Assert.assertEquals("HTTPS required", testAccountPage.getErrorMessage());
+    }
+    
+    private Set<String> getCookieNames() {
+        Set<Cookie> cookies = driver.manage().getCookies();
+        Set<String> cookieNames = new HashSet<>();
+        for (Cookie cookie : cookies) {
+            cookieNames.add(cookie.getName());
+        }
+        return cookieNames;
+    }
+}
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..e156c39
--- /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", "", false);
+        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..0df9c15
--- /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", false);
+        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, "", false));
+        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, "", false);
+            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..9d3a8c1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java
@@ -0,0 +1,90 @@
+package org.keycloak.testsuite.util;
+
+import com.icegreen.greenmail.util.GreenMail;
+import com.icegreen.greenmail.util.ServerSetup;
+import java.io.IOException;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.net.SocketException;
+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)");
+            // Suppress error from GreenMail on shutdown
+            Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+                @Override
+                public void uncaughtException(Thread t, Throwable e) {
+                    if (!(e.getCause() instanceof SocketException && e.getStackTrace()[0].getClassName()
+                            .equals("com.icegreen.greenmail.smtp.SmtpHandler"))) {
+                        log.error("Exception in thread \"" + t.getName() + "\" ");
+                        log.error(e.getMessage(), e);
+                    }
+                }
+            });
+            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..9ac97d0
--- /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.javax.persistence.artifactId}</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>
diff --git a/testsuite/jetty/jetty81/pom.xml b/testsuite/jetty/jetty81/pom.xml
index 5fd9e6a..a675c2d 100755
--- a/testsuite/jetty/jetty81/pom.xml
+++ b/testsuite/jetty/jetty81/pom.xml
@@ -144,7 +144,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
diff --git a/testsuite/jetty/jetty91/pom.xml b/testsuite/jetty/jetty91/pom.xml
index 7815e73..ead665b 100755
--- a/testsuite/jetty/jetty91/pom.xml
+++ b/testsuite/jetty/jetty91/pom.xml
@@ -144,7 +144,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
diff --git a/testsuite/jetty/jetty92/pom.xml b/testsuite/jetty/jetty92/pom.xml
index 09eaec7..ea9f7e3 100755
--- a/testsuite/jetty/jetty92/pom.xml
+++ b/testsuite/jetty/jetty92/pom.xml
@@ -144,7 +144,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
diff --git a/testsuite/performance/pom.xml b/testsuite/performance/pom.xml
index f553ab7..03bf3fe 100755
--- a/testsuite/performance/pom.xml
+++ b/testsuite/performance/pom.xml
@@ -193,7 +193,7 @@
 
                             <dependency>
                                 <groupId>org.hibernate.javax.persistence</groupId>
-                                <artifactId>hibernate-jpa-2.1-api</artifactId>
+                                <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
                                 <version>${hibernate.javax.persistence.version}</version>
                             </dependency>
                             <dependency>
diff --git a/testsuite/proxy/pom.xml b/testsuite/proxy/pom.xml
index 28c418a..df5896c 100755
--- a/testsuite/proxy/pom.xml
+++ b/testsuite/proxy/pom.xml
@@ -139,7 +139,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
diff --git a/testsuite/tomcat6/pom.xml b/testsuite/tomcat6/pom.xml
index 0597e7d..498c4d6 100755
--- a/testsuite/tomcat6/pom.xml
+++ b/testsuite/tomcat6/pom.xml
@@ -130,7 +130,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
diff --git a/testsuite/tomcat7/pom.xml b/testsuite/tomcat7/pom.xml
index b8a44e3..d807e73 100755
--- a/testsuite/tomcat7/pom.xml
+++ b/testsuite/tomcat7/pom.xml
@@ -150,7 +150,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
diff --git a/testsuite/tomcat8/pom.xml b/testsuite/tomcat8/pom.xml
index 4862aeb..e2a9059 100755
--- a/testsuite/tomcat8/pom.xml
+++ b/testsuite/tomcat8/pom.xml
@@ -134,7 +134,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
diff --git a/testsuite/wildfly/pom.xml b/testsuite/wildfly/pom.xml
index d91657e..fd5c195 100644
--- a/testsuite/wildfly/pom.xml
+++ b/testsuite/wildfly/pom.xml
@@ -141,7 +141,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>