keycloak-memoizeit

Changes

examples/authz/hello-world/hello-world-authz-realm.json 49(+0 -49)

examples/authz/hello-world/hello-world-authz-service.json 30(+0 -30)

examples/authz/hello-world/pom.xml 43(+0 -43)

examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java 154(+0 -154)

examples/authz/hello-world/src/main/resources/keycloak.json 8(+0 -8)

examples/authz/hello-world-authz-service/hello-world-authz-realm.json 48(+0 -48)

examples/authz/hello-world-authz-service/hello-world-authz-service.json 36(+0 -36)

examples/authz/hello-world-authz-service/pom.xml 54(+0 -54)

examples/authz/hello-world-authz-service/README.md 47(+0 -47)

examples/authz/hello-world-authz-service/src/main/webapp/error.jsp 30(+0 -30)

examples/authz/hello-world-authz-service/src/main/webapp/index.jsp 49(+0 -49)

examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json 12(+0 -12)

examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/web.xml 45(+0 -45)

examples/authz/photoz/photoz-authz-policy/pom.xml 22(+0 -22)

examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl 14(+0 -14)

examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.resource.owner/Main.drl 15(+0 -15)

examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl 14(+0 -14)

examples/authz/photoz/photoz-authz-policy/src/main/resources/com/photoz/authz/policy/contextual/Main.drl 15(+0 -15)

examples/authz/photoz/photoz-authz-policy/src/main/resources/META-INF/kmodule.xml 21(+0 -21)

examples/authz/photoz/photoz-html5-client/pom.xml 37(+0 -37)

examples/authz/photoz/photoz-html5-client/src/main/webapp/index.html 31(+0 -31)

examples/authz/photoz/photoz-html5-client/src/main/webapp/js/app.js 226(+0 -226)

examples/authz/photoz/photoz-html5-client/src/main/webapp/js/identity.js 64(+0 -64)

examples/authz/photoz/photoz-html5-client/src/main/webapp/keycloak.json 7(+0 -7)

examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular.min.js 214(+0 -214)

examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-resource.min.js 13(+0 -13)

examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-route.min.js 14(+0 -14)

examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/jwt-decode.min.js 1(+0 -1)

examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/admin/albums.html 19(+0 -19)

examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/album/create.html 7(+0 -7)

examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/album/detail.html 1(+0 -1)

examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/home.html 22(+0 -22)

examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/profile.html 6(+0 -6)

examples/authz/photoz/photoz-html5-client/src/main/webapp/WEB-INF/web.xml 9(+0 -9)

examples/authz/photoz/photoz-realm.json 132(+0 -132)

examples/authz/photoz/photoz-restful-api/pom.xml 81(+0 -81)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java 181(+0 -181)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java 67(+0 -67)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/SharedAlbum.java 47(+0 -47)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java 91(+0 -91)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java 81(+0 -81)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/ErrorResponse.java 32(+0 -32)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/PhotozApplication.java 12(+0 -12)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Resources.java 51(+0 -51)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Transaction.java 33(+0 -33)

examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java 56(+0 -56)

examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml 23(+0 -23)

examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json 152(+0 -152)

examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml 27(+0 -27)

examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/keycloak.json 42(+0 -42)

examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml 41(+0 -41)

examples/authz/photoz/pom.xml 24(+0 -24)

examples/authz/photoz/README.md 100(+0 -100)

examples/authz/pom.xml 30(+0 -30)

examples/authz/servlet-authz/pom.xml 54(+0 -54)

examples/authz/servlet-authz/README.md 54(+0 -54)

examples/authz/servlet-authz/servlet-authz-app-config.json 145(+0 -145)

examples/authz/servlet-authz/servlet-authz-realm.json 95(+0 -95)

examples/authz/servlet-authz/src/main/webapp/accessDenied.jsp 6(+0 -6)

examples/authz/servlet-authz/src/main/webapp/index.jsp 35(+0 -35)

examples/authz/servlet-authz/src/main/webapp/logout-include.jsp 11(+0 -11)

examples/authz/servlet-authz/src/main/webapp/META-INF/jboss-deployment-structure.xml 25(+0 -25)

examples/authz/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp 6(+0 -6)

examples/authz/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp 48(+0 -48)

examples/authz/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp 6(+0 -6)

examples/authz/servlet-authz/src/main/webapp/WEB-INF/keycloak.json 10(+0 -10)

examples/authz/servlet-authz/src/main/webapp/WEB-INF/web.xml 43(+0 -43)

examples/pom.xml 1(+0 -1)

services/pom.xml 43(+22 -21)

testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml 9(+0 -9)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/InputPage.java 52(+0 -52)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/InputServlet.java 81(+0 -81)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java 242(+0 -242)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java 152(+0 -152)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlSPFacade.java 62(+0 -62)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/samlfilter/SamlAdapterTest.java 168(+0 -168)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keycloak-saml.xml 64(+0 -64)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml 59(+0 -59)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keycloak-saml.xml 64(+0 -64)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keycloak-saml.xml 64(+0 -64)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/mappers/WEB-INF/keycloak-saml.xml 44(+0 -44)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml 62(+0 -62)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml 62(+0 -62)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keycloak-saml.xml 63(+0 -63)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-get/WEB-INF/keycloak-saml.xml 63(+0 -63)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-get/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keycloak-saml.xml 64(+0 -64)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml 59(+0 -59)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keycloak-saml.xml 63(+0 -63)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keycloak-saml.xml 64(+0 -64)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keycloak-saml.xml 64(+0 -64)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keystore.jks 0(+0 -0)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml 43(+0 -43)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/simple-post/WEB-INF/keycloak-saml.xml 43(+0 -43)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/simple-post2/WEB-INF/keycloak-saml.xml 43(+0 -43)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/simple-post-passive/WEB-INF/keycloak-saml.xml 44(+0 -44)

Details

diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
index 8e83de1..8bec840 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
@@ -95,7 +95,9 @@ class PathMatcher {
                 }
 
                 if (WILDCARD == expectedUri.charAt(expectedUri.length() - 1)) {
-                    matchingAnyPath = entry;
+                    if (matchingAnyPath == null || matchingAnyPath.getPath().length() < matchingUri.length()) {
+                        matchingAnyPath = entry;
+                    }
                 } else {
                     int suffixIndex = expectedUri.indexOf(WILDCARD + ".");
 
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java b/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java
index 1bf5c86..df24fdb 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java
@@ -97,7 +97,7 @@ public class AuthzClient {
      * @return a {@link ProtectionResource}
      */
     public ProtectionResource protection() {
-        return new ProtectionResource(this.http, this.serverConfiguration, createPatSupplier());
+        return new ProtectionResource(this.http, this.serverConfiguration, configuration, createPatSupplier());
     }
 
     /**
@@ -107,7 +107,7 @@ public class AuthzClient {
      * @return a {@link ProtectionResource}
      */
     public ProtectionResource protection(final String accessToken) {
-        return new ProtectionResource(this.http, this.serverConfiguration, new TokenCallable(http, configuration, serverConfiguration) {
+        return new ProtectionResource(this.http, this.serverConfiguration, configuration, new TokenCallable(http, configuration, serverConfiguration) {
             @Override
             public String call() {
                 return accessToken;
@@ -128,7 +128,7 @@ public class AuthzClient {
      * @return a {@link ProtectionResource}
      */
     public ProtectionResource protection(String userName, String password) {
-        return new ProtectionResource(this.http, this.serverConfiguration, createPatSupplier(userName, password));
+        return new ProtectionResource(this.http, this.serverConfiguration, configuration, createPatSupplier(userName, password));
     }
 
     /**
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
index cc92712..cf2e91a 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
 
+import org.keycloak.authorization.client.Configuration;
 import org.keycloak.authorization.client.representation.ResourceRepresentation;
 import org.keycloak.authorization.client.representation.ServerConfiguration;
 import org.keycloak.authorization.client.util.Http;
@@ -38,11 +39,13 @@ public class ProtectedResource {
 
     private final Http http;
     private ServerConfiguration serverConfiguration;
+    private final Configuration configuration;
     private final TokenCallable pat;
 
-    ProtectedResource(Http http, ServerConfiguration serverConfiguration, TokenCallable pat) {
+    ProtectedResource(Http http, ServerConfiguration serverConfiguration, Configuration configuration, TokenCallable pat) {
         this.http = http;
         this.serverConfiguration = serverConfiguration;
+        this.configuration = configuration;
         this.pat = pat;
     }
 
@@ -119,13 +122,30 @@ public class ProtectedResource {
     }
 
     /**
-     * Query the server for a resource given its <code>name</code>.
+     * Query the server for a resource given its <code>name</code> where the owner is the resource server itself.
      *
      * @param id the resource name
      * @return a {@link ResourceRepresentation}
      */
     public ResourceRepresentation findByName(String name) {
-        String[] representations = find(null, name, null, null, null, null, null, null);
+        String[] representations = find(null, name, null, configuration.getResource(), null, null, null, null);
+
+        if (representations.length == 0) {
+            return null;
+        }
+
+        return findById(representations[0]);
+    }
+
+    /**
+     * Query the server for a resource given its <code>name</code> and a given <code>ownerId</code>.
+     *
+     * @param name the resource name
+     * @param ownerId the owner id
+     * @return a {@link ResourceRepresentation}
+     */
+    public ResourceRepresentation findByName(String name, String ownerId) {
+        String[] representations = find(null, name, null, ownerId, null, null, null, null);
 
         if (representations.length == 0) {
             return null;
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java
index 7268fe9..03fa945 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java
@@ -17,6 +17,7 @@
  */
 package org.keycloak.authorization.client.resource;
 
+import org.keycloak.authorization.client.Configuration;
 import org.keycloak.authorization.client.representation.ServerConfiguration;
 import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
 import org.keycloak.authorization.client.util.Http;
@@ -31,15 +32,17 @@ public class ProtectionResource {
 
     private final TokenCallable pat;
     private final Http http;
+    private final Configuration configuration;
     private ServerConfiguration serverConfiguration;
 
-    public ProtectionResource(Http http, ServerConfiguration serverConfiguration, TokenCallable pat) {
+    public ProtectionResource(Http http, ServerConfiguration serverConfiguration, Configuration configuration, TokenCallable pat) {
         if (pat == null) {
             throw new RuntimeException("No access token was provided when creating client for Protection API.");
         }
 
         this.http = http;
         this.serverConfiguration = serverConfiguration;
+        this.configuration = configuration;
         this.pat = pat;
     }
 
@@ -49,7 +52,7 @@ public class ProtectionResource {
      * @return a {@link ProtectedResource}
      */
     public ProtectedResource resource() {
-        return new ProtectedResource(http, serverConfiguration, pat);
+        return new ProtectedResource(http, serverConfiguration, configuration, pat);
     }
 
     /**
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
index 3531f40..ed20a67 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
@@ -44,4 +44,12 @@ public class HttpResponseException extends RuntimeException {
     public byte[] getBytes() {
         return bytes;
     }
+
+    @Override
+    public String toString() {
+        if (bytes != null) {
+            return new StringBuilder(super.toString()).append(" / Response from server: ").append(new String(bytes)).toString();
+        }
+        return super.toString();
+    }
 }
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/Throwables.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/Throwables.java
index ae2eaf1..2b0b79a 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/util/Throwables.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/Throwables.java
@@ -39,7 +39,7 @@ public final class Throwables {
      */
     public static RuntimeException handleWrapException(String message, Throwable cause) {
         if (cause instanceof HttpResponseException) {
-            throw handleAndWrapHttpResponseException(message, HttpResponseException.class.cast(cause));
+            throw handleAndWrapHttpResponseException(HttpResponseException.class.cast(cause));
         }
 
         return new RuntimeException(message, cause);
@@ -91,19 +91,11 @@ public final class Throwables {
         throw new RuntimeException(message, cause);
     }
 
-    private static RuntimeException handleAndWrapHttpResponseException(String message, HttpResponseException exception) {
-        HttpResponseException hre = HttpResponseException.class.cast(exception);
-        StringBuilder detail = new StringBuilder(message);
-        byte[] bytes = hre.getBytes();
-
-        if (bytes != null) {
-            detail.append(". Server message: ").append(new String(bytes));
-        }
-
+    private static RuntimeException handleAndWrapHttpResponseException(HttpResponseException exception) {
         if (403 == exception.getStatusCode()) {
-            throw new AuthorizationDeniedException(detail.toString(), exception);
+            throw new AuthorizationDeniedException(exception);
         }
 
-        return new RuntimeException(detail.toString(), exception);
+        return new RuntimeException(exception);
     }
 }
diff --git a/core/src/main/java/org/keycloak/representations/IDToken.java b/core/src/main/java/org/keycloak/representations/IDToken.java
index 51776f0..76842bf 100755
--- a/core/src/main/java/org/keycloak/representations/IDToken.java
+++ b/core/src/main/java/org/keycloak/representations/IDToken.java
@@ -51,6 +51,10 @@ public class IDToken extends JsonWebToken {
     public static final String CLAIMS_LOCALES = "claims_locales";
     public static final String ACR = "acr";
 
+    // Financial API - Part 2: Read and Write API Security Profile
+    // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+    public static final String S_HASH = "s_hash";
+
     // NOTE!!!  WE used to use @JsonUnwrapped on a UserClaimSet object.  This screws up otherClaims and the won't work
     // anymore.  So don't have any @JsonUnwrapped!
     @JsonProperty(NONCE)
@@ -131,6 +135,11 @@ public class IDToken extends JsonWebToken {
     @JsonProperty(ACR)
     protected String acr;
 
+    // Financial API - Part 2: Read and Write API Security Profile
+    // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+    @JsonProperty(S_HASH)
+    protected String stateHash; 
+
     public String getNonce() {
         return nonce;
     }
@@ -338,4 +347,14 @@ public class IDToken extends JsonWebToken {
     public void setAcr(String acr) {
         this.acr = acr;
     }
+
+    // Financial API - Part 2: Read and Write API Security Profile
+    // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+    public String getStateHash() {
+        return stateHash;
+    }
+
+    public void setStateHash(String stateHash) {
+        this.stateHash = stateHash;
+    }
 }
diff --git a/distribution/api-docs-dist/assembly.xml b/distribution/api-docs-dist/assembly.xml
index f32d988..6e4ee6e 100755
--- a/distribution/api-docs-dist/assembly.xml
+++ b/distribution/api-docs-dist/assembly.xml
@@ -39,6 +39,7 @@
         <file>
             <source>src/index.html</source>
             <outputDirectory></outputDirectory>
+            <filtered>true</filtered>
         </file>
     </files>
 
diff --git a/distribution/api-docs-dist/pom.xml b/distribution/api-docs-dist/pom.xml
index 59b994e..88bcf69 100755
--- a/distribution/api-docs-dist/pom.xml
+++ b/distribution/api-docs-dist/pom.xml
@@ -29,13 +29,9 @@
     <name>Keycloak Docs Distribution</name>
     <description/>
 
-    <dependencies>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-dependencies-server-all</artifactId>
-            <type>pom</type>
-        </dependency>
-    </dependencies>
+    <properties>
+        <javadoc.branding>${product.name.full} ${product.version}</javadoc.branding>
+    </properties>
 
     <build>
         <finalName>keycloak-api-docs-${project.version}</finalName>
@@ -45,12 +41,9 @@
                 <artifactId>maven-javadoc-plugin</artifactId>
                 <configuration>
                     <minmemory>128m</minmemory>
-                    <maxmemory>1024m</maxmemory>
-                    <dependencySourceIncludes>
-                        <dependencySourceInclude>org.keycloak:*</dependencySourceInclude>
-                    </dependencySourceIncludes>
+                    <maxmemory>2400m</maxmemory>
+                    <encoding>UTF-8</encoding>
                     <includeDependencySources>true</includeDependencySources>
-                    <includeTransitiveDependencySources>true</includeTransitiveDependencySources>
                 </configuration>
                 <executions>
                     <execution>
@@ -75,12 +68,6 @@
                             <descriptors>
                                 <descriptor>assembly.xml</descriptor>
                             </descriptors>
-                            <outputDirectory>
-                                target
-                            </outputDirectory>
-                            <workDirectory>
-                                target/assembly/work
-                            </workDirectory>
                             <appendAssemblyId>false</appendAssemblyId>
                         </configuration>
                     </execution>
@@ -89,7 +76,6 @@
         </plugins>
     </build>
 
-
     <profiles>
         <profile>
             <id>community</id>
@@ -98,10 +84,32 @@
                     <name>!product</name>
                 </property>
             </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-dependencies-server-all</artifactId>
+                    <type>pom</type>
+                </dependency>
+            </dependencies>
             <build>
                 <plugins>
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>aggregate-javadoc</id>
+                                <configuration>
+                                    <includeTransitiveDependencySources>true</includeTransitiveDependencySources>
+                                    <dependencySourceIncludes>
+                                        <dependencySourceInclude>org.keycloak:*</dependencySourceInclude>
+                                    </dependencySourceIncludes>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-deploy-plugin</artifactId>
                         <configuration>
                             <skip>true</skip>
@@ -110,6 +118,76 @@
                 </plugins>
             </build>
         </profile>
+
+        <profile>
+            <id>product</id>
+            <activation>
+                <property>
+                    <name>product</name>
+                </property>
+            </activation>
+            <!-- Make sure to keep this list in sync with <dependencySourceIncludes> -->
+            <dependencies>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-server-spi</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-common</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-core</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-saml-core-public</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-adapter-spi</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-adapter-core</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-saml-adapter-api-public</artifactId>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>aggregate-javadoc</id>
+                                <configuration>
+                                    <windowtitle>${javadoc.branding} public API</windowtitle>
+                                    <doctitle>${javadoc.branding} public API</doctitle>
+                                    <header>${javadoc.branding}</header>
+                                    <footer>${javadoc.branding}</footer>
+                                    <includeTransitiveDependencySources>false</includeTransitiveDependencySources>
+                                    <!-- Make sure to keep this list in sync with <dependencies> -->
+                                    <dependencySourceIncludes>
+                                        <include>org.keycloak:keycloak-server-spi</include>
+                                        <include>org.keycloak:keycloak-common</include>
+                                        <include>org.keycloak:keycloak-core</include>
+                                        <include>org.keycloak:keycloak-saml-core-public</include>
+                                        <include>org.keycloak:keycloak-adapter-spi</include>
+                                        <include>org.keycloak:keycloak-adapter-core</include>
+                                        <include>org.keycloak:keycloak-saml-adapter-api-public</include>
+                                    </dependencySourceIncludes>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
 
 </project>
diff --git a/distribution/api-docs-dist/src/index.html b/distribution/api-docs-dist/src/index.html
index 38f86e9..97a8028 100755
--- a/distribution/api-docs-dist/src/index.html
+++ b/distribution/api-docs-dist/src/index.html
@@ -24,7 +24,7 @@
 </head>
 
 <body>
-<h1>Keyloak API Documentation</h1>
+<h1>${product.name.full} API Documentation</h1>
 <table>
     <tr>
         <td>Admin REST API</td>
@@ -35,4 +35,4 @@
         <td colspan="3"><a href="javadocs/index.html">HTML</a></td>
     </tr>
 </body>
-</html>
\ No newline at end of file
+</html>

examples/pom.xml 1(+0 -1)

diff --git a/examples/pom.xml b/examples/pom.xml
index 7572bc4..2313c39 100755
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -66,6 +66,5 @@
         <module>themes</module>
         <module>saml</module>
         <module>ldap</module>
-        <module>authz</module>
     </modules>
 </project>
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java
index e7daaa1..7f2c394 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java
@@ -62,5 +62,10 @@ public interface ResourcesResource {
     @GET
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
+    List<ResourceRepresentation> findByName(@QueryParam("name") String name, @QueryParam("owner") String owner);
+
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
     List<ResourceRepresentation> resources();
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java
index 5513777..c1f8914 100644
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java
@@ -18,6 +18,7 @@
 package org.keycloak.connections.infinispan;
 
 import org.infinispan.Cache;
+import org.infinispan.client.hotrod.RemoteCache;
 import org.infinispan.manager.EmbeddedCacheManager;
 
 /**
@@ -26,11 +27,13 @@ import org.infinispan.manager.EmbeddedCacheManager;
 public class DefaultInfinispanConnectionProvider implements InfinispanConnectionProvider {
 
     private final EmbeddedCacheManager cacheManager;
+    private final RemoteCacheProvider remoteCacheProvider;
     private final String siteName;
     private final String nodeName;
 
-    public DefaultInfinispanConnectionProvider(EmbeddedCacheManager cacheManager, String nodeName, String siteName) {
+    public DefaultInfinispanConnectionProvider(EmbeddedCacheManager cacheManager, RemoteCacheProvider remoteCacheProvider, String nodeName, String siteName) {
         this.cacheManager = cacheManager;
+        this.remoteCacheProvider = remoteCacheProvider;
         this.nodeName = nodeName;
         this.siteName = siteName;
     }
@@ -41,6 +44,11 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection
     }
 
     @Override
+    public <K, V> RemoteCache<K, V> getRemoteCache(String cacheName) {
+        return remoteCacheProvider.getRemoteCache(cacheName);
+    }
+
+    @Override
     public String getNodeName() {
         return nodeName;
     }
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
index 7493cae..0053791 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
@@ -56,6 +56,8 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
 
     protected EmbeddedCacheManager cacheManager;
 
+    protected RemoteCacheProvider remoteCacheProvider;
+
     protected boolean containerManaged;
 
     private String nodeName;
@@ -66,7 +68,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
     public InfinispanConnectionProvider create(KeycloakSession session) {
         lazyInit();
 
-        return new DefaultInfinispanConnectionProvider(cacheManager, nodeName, siteName);
+        return new DefaultInfinispanConnectionProvider(cacheManager, remoteCacheProvider, nodeName, siteName);
     }
 
     @Override
@@ -74,6 +76,9 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
         if (cacheManager != null && !containerManaged) {
             cacheManager.stop();
         }
+        if (remoteCacheProvider != null) {
+            remoteCacheProvider.stop();
+        }
         cacheManager = null;
     }
 
@@ -104,6 +109,8 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
                     }
 
                     logger.infof("Node name: %s, Site name: %s", nodeName, siteName);
+
+                    remoteCacheProvider = new RemoteCacheProvider(config, cacheManager);
                 }
             }
         }
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
index 00f60a7..cb23b6f 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
@@ -18,6 +18,7 @@
 package org.keycloak.connections.infinispan;
 
 import org.infinispan.Cache;
+import org.infinispan.client.hotrod.RemoteCache;
 import org.keycloak.provider.Provider;
 
 /**
@@ -68,6 +69,12 @@ public interface InfinispanConnectionProvider extends Provider {
     <K, V> Cache<K, V> getCache(String name);
 
     /**
+     * Get remote cache of given name. Could just retrieve the remote cache from the remoteStore configured in given infinispan cache and/or
+     * alternatively return the secured remoteCache (remoteCache corresponding to secured hotrod endpoint)
+     */
+    <K, V> RemoteCache<K, V> getRemoteCache(String name);
+
+    /**
      * @return Address of current node in cluster. In non-cluster environment, it returns some other non-null value (eg. hostname with some random value like "host-123456" )
      */
     String getNodeName();
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/RemoteCacheProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/RemoteCacheProvider.java
new file mode 100644
index 0000000..055e89b
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/RemoteCacheProvider.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.connections.infinispan;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.RealmCallback;
+
+import org.infinispan.client.hotrod.RemoteCache;
+import org.infinispan.client.hotrod.RemoteCacheManager;
+import org.infinispan.client.hotrod.configuration.Configuration;
+import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.jboss.logging.Logger;
+import org.keycloak.Config;
+import org.keycloak.common.util.reflections.Reflections;
+import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
+import java.util.stream.Collectors;
+import org.infinispan.client.hotrod.exceptions.HotRodClientException;
+
+/**
+ * Get either just remoteCache associated with remoteStore associated with infinispan cache of given name. If security is enabled, then
+ * return secured remoteCache based on the template provided by remoteStore configuration but with added "authentication" configuration
+ * of secured hotrod endpoint (RemoteStore doesn't yet allow to configure "security" of hotrod endpoints)
+ *
+ * TODO: Remove this class once we upgrade to infinispan version, which allows to configure security for remoteStore itself
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class RemoteCacheProvider {
+
+    public static final String SCRIPT_CACHE_NAME = "___script_cache";
+
+    protected static final Logger logger = Logger.getLogger(RemoteCacheProvider.class);
+
+    private final Config.Scope config;
+    private final EmbeddedCacheManager cacheManager;
+
+    private final Map<String, RemoteCache> availableCaches = new HashMap<>();
+
+    // Enlist secured managers, which are managed by us and should be shutdown on stop
+    private final Map<String, RemoteCacheManager> managedManagers = new HashMap<>();
+
+    public RemoteCacheProvider(Config.Scope config, EmbeddedCacheManager cacheManager) {
+        this.config = config;
+        this.cacheManager = cacheManager;
+    }
+
+    public RemoteCache getRemoteCache(String cacheName) {
+        if (availableCaches.get(cacheName) == null) {
+            synchronized (this) {
+                if (availableCaches.get(cacheName) == null) {
+                    RemoteCache remoteCache = loadRemoteCache(cacheName);
+                    availableCaches.put(cacheName, remoteCache);
+                }
+            }
+        }
+
+        return availableCaches.get(cacheName);
+    }
+
+    public void stop() {
+        logger.debugf("Shutdown %d registered secured remoteCache managers", managedManagers.size());
+
+        for (RemoteCacheManager mgr : managedManagers.values()) {
+            mgr.stop();
+        }
+    }
+
+
+    protected synchronized RemoteCache loadRemoteCache(String cacheName) {
+        RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cacheManager.getCache(cacheName));
+
+        Boolean remoteStoreSecurity = config.getBoolean("remoteStoreSecurityEnabled");
+        if (remoteStoreSecurity == null) {
+            try {
+                logger.debugf("Detecting remote security settings of HotRod server, cache %s. Disable by explicitly setting \"remoteStoreSecurityEnabled\" property in spi=connectionsInfinispan/provider=default", cacheName);
+                remoteStoreSecurity = false;
+                final RemoteCache<Object, Object> scriptCache = remoteCache.getRemoteCacheManager().getCache(SCRIPT_CACHE_NAME);
+                if (scriptCache == null) {
+                    logger.debug("Cannot detect remote security settings of HotRod server, disabling.");
+                } else {
+                    scriptCache.containsKey("");
+                }
+            } catch (HotRodClientException ex) {
+                logger.debug("Seems that HotRod server requires authentication, enabling.");
+                remoteStoreSecurity = true;
+            }
+        }
+
+        if (remoteStoreSecurity) {
+            logger.infof("Remote store security for cache %s is enabled. Disable by setting \"remoteStoreSecurityEnabled\" property to \"false\" in spi=connectionsInfinispan/provider=default", cacheName);
+            RemoteCacheManager securedMgr = getOrCreateSecuredRemoteCacheManager(config, cacheName, remoteCache.getRemoteCacheManager());
+            return securedMgr.getCache(remoteCache.getName());
+        } else {
+            logger.infof("Remote store security for cache %s is disabled. If server fails to connect to remote JDG server, enable it.", cacheName);
+            return remoteCache;
+        }
+    }
+
+
+    protected RemoteCacheManager getOrCreateSecuredRemoteCacheManager(Config.Scope config, String cacheName, RemoteCacheManager origManager) {
+        String serverName = config.get("remoteStoreSecurityServerName", "keycloak-jdg-server");
+        String realm = config.get("remoteStoreSecurityRealm", "AllowScriptManager");
+
+        String username = config.get("remoteStoreSecurityUsername", "___script_manager");
+        String password = config.get("remoteStoreSecurityPassword", "not-so-secret-password");
+
+        // Create configuration template from the original configuration provided at remoteStore level
+        Configuration origConfig = origManager.getConfiguration();
+
+        ConfigurationBuilder cfgBuilder = new ConfigurationBuilder()
+                .read(origConfig);
+
+        String securedHotRodEndpoint = origConfig.servers().stream()
+              .map(serverConfiguration -> serverConfiguration.host() + ":" + serverConfiguration.port())
+              .collect(Collectors.joining(";"));
+
+        if (managedManagers.containsKey(securedHotRodEndpoint)) {
+            return managedManagers.get(securedHotRodEndpoint);
+        }
+
+        logger.infof("Creating secured RemoteCacheManager for Server: '%s', Cache: '%s', Realm: '%s', Username: '%s', Secured HotRod endpoint: '%s'", serverName, cacheName, realm, username, securedHotRodEndpoint);
+
+        // Workaround as I need a way to override servers and it's not possible to remove existing :/
+        try {
+            Field serversField = cfgBuilder.getClass().getDeclaredField("servers");
+            Reflections.setAccessible(serversField);
+            List origServers = Reflections.getFieldValue(serversField, cfgBuilder, List.class);
+            origServers.clear();
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        }
+
+        // Create configuration based on the configuration template from remoteStore. Just add security and override secured endpoint
+        Configuration newConfig = cfgBuilder
+                .addServers(securedHotRodEndpoint)
+                .security()
+                  .authentication()
+                    .serverName(serverName) //define server name, should be specified in XML configuration on JDG side
+                    .saslMechanism("DIGEST-MD5") // define SASL mechanism, in this example we use DIGEST with MD5 hash
+                    .callbackHandler(new LoginHandler(username, password.toCharArray(), realm)) // define login handler, implementation defined
+                    .enable()
+                .build();
+
+        final RemoteCacheManager remoteCacheManager = new RemoteCacheManager(newConfig);
+        managedManagers.put(securedHotRodEndpoint, remoteCacheManager);
+        return remoteCacheManager;
+    }
+
+
+    private static class LoginHandler implements CallbackHandler {
+        final private String login;
+        final private char[] password;
+        final private String realm;
+
+        private LoginHandler(String login, char[] password, String realm) {
+            this.login = login;
+            this.password = password;
+            this.realm = realm;
+        }
+
+        @Override
+        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+            for (Callback callback : callbacks) {
+                if (callback instanceof NameCallback) {
+                    ((NameCallback) callback).setName(login);
+                } else if (callback instanceof PasswordCallback) {
+                    ((PasswordCallback) callback).setPassword(password);
+                } else if (callback instanceof RealmCallback) {
+                    ((RealmCallback) callback).setText(realm);
+                } else {
+                    throw new UnsupportedCallbackException(callback);
+                }
+            }
+        }
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
index 0f245ee..e54316d 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
@@ -79,7 +79,7 @@ public class StoreFactoryCacheManager extends CacheManager {
 
     public void resourceUpdated(String id, String name, String type, String uri, Set<String> scopes, String serverId, String owner, Set<String> invalidations) {
         invalidations.add(id);
-        invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, serverId));
+        invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, owner, serverId));
         invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
         invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, null));
         invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(id, serverId));
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
index c50cec1..5924573 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
@@ -336,8 +336,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         return "scope.name." + name + "." + serverId;
     }
 
-    public static String getResourceByNameCacheKey(String name, String serverId) {
-        return "resource.name." + name + "." + serverId;
+    public static String getResourceByNameCacheKey(String name, String ownerId, String serverId) {
+        return "resource.name." + name + "." + ownerId + "." + serverId;
     }
 
     public static String getResourceByOwnerCacheKey(String owner, String serverId) {
@@ -580,17 +580,22 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
 
         @Override
         public Resource findByName(String name, String resourceServerId) {
+            return findByName(name, resourceServerId, resourceServerId);
+        }
+
+        @Override
+        public Resource findByName(String name, String ownerId, String resourceServerId) {
             if (name == null) return null;
-            String cacheKey = getResourceByNameCacheKey(name, resourceServerId);
+            String cacheKey = getResourceByNameCacheKey(name, ownerId, resourceServerId);
             List<Resource> result = cacheQuery(cacheKey, ResourceListQuery.class, () -> {
-                Resource resource = getResourceStoreDelegate().findByName(name, resourceServerId);
+                        Resource resource = getResourceStoreDelegate().findByName(name, ownerId, resourceServerId);
 
-                if (resource == null) {
-                    return Collections.emptyList();
-                }
+                        if (resource == null) {
+                            return Collections.emptyList();
+                        }
 
-                return Arrays.asList(resource);
-            },
+                        return Arrays.asList(resource);
+                    },
                     (revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
 
             if (result.isEmpty()) {
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java
index 4ecd445..53b294c 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java
@@ -27,12 +27,12 @@ import org.infinispan.commons.marshall.Marshaller;
 import org.infinispan.context.Flag;
 import org.jboss.logging.Logger;
 import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.connections.infinispan.RemoteCacheProvider;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
 import org.keycloak.models.sessions.infinispan.initializer.BaseCacheInitializer;
 import org.keycloak.models.sessions.infinispan.initializer.OfflinePersistentUserSessionLoader;
 import org.keycloak.models.sessions.infinispan.initializer.SessionLoader;
-import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -87,9 +87,9 @@ public class RemoteCacheSessionsLoader implements SessionLoader {
 
     @Override
     public void init(KeycloakSession session) {
-        RemoteCache remoteCache = InfinispanUtil.getRemoteCache(getCache(session));
+        RemoteCache remoteCache = getRemoteCache(session);
 
-        RemoteCache<String, String> scriptCache = remoteCache.getRemoteCacheManager().getCache("___script_cache");
+        RemoteCache<String, String> scriptCache = remoteCache.getRemoteCacheManager().getCache(RemoteCacheProvider.SCRIPT_CACHE_NAME);
 
         if (!scriptCache.containsKey("load-sessions.js")) {
             scriptCache.put("load-sessions.js",
@@ -100,7 +100,7 @@ public class RemoteCacheSessionsLoader implements SessionLoader {
 
     @Override
     public int getSessionsCount(KeycloakSession session) {
-        RemoteCache remoteCache = InfinispanUtil.getRemoteCache(getCache(session));
+        RemoteCache remoteCache = getRemoteCache(session);
         return remoteCache.size();
     }
 
@@ -109,7 +109,7 @@ public class RemoteCacheSessionsLoader implements SessionLoader {
         Cache cache = getCache(session);
         Cache decoratedCache = cache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD, Flag.SKIP_CACHE_STORE, Flag.IGNORE_RETURN_VALUES);
 
-        RemoteCache<?, ?> remoteCache = InfinispanUtil.getRemoteCache(cache);
+        RemoteCache<?, ?> remoteCache = getRemoteCache(session);
 
         log.debugf("Will do bulk load of sessions from remote cache '%s' . First: %d, max: %d", cache.getName(), first, max);
 
@@ -167,4 +167,10 @@ public class RemoteCacheSessionsLoader implements SessionLoader {
     public void afterAllSessionsLoaded(BaseCacheInitializer initializer) {
 
     }
+
+    // Get remoteCache, which may be secured
+    private RemoteCache getRemoteCache(KeycloakSession session) {
+        InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
+        return ispn.getRemoteCache(cacheName);
+    }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
index e62fdd9..7bd7ec4 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
@@ -125,7 +125,7 @@ public class UserSessionAdapter implements UserSessionModel {
 
     @Override
     public void removeAuthenticatedClientSessions(Collection<String> removedClientUUIDS) {
-        if (removedClientUUIDS == null || ! removedClientUUIDS.isEmpty()) {
+        if (removedClientUUIDS == null || removedClientUUIDS.isEmpty()) {
             return;
         }
 
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
index 6031a6e..861853a 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
@@ -47,7 +47,7 @@ import java.util.List;
                 @NamedQuery(name="findResourceIdByOwner", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner"),
                 @NamedQuery(name="findAnyResourceIdByOwner", query="select r.id from ResourceEntity r where r.owner = :owner"),
                 @NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId  and r.uri = :uri"),
-                @NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId  and r.name = :name"),
+                @NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId  and r.owner = :ownerId and r.name = :name"),
                 @NamedQuery(name="findResourceIdByType", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId  and r.type = :type"),
                 @NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId "),
                 @NamedQuery(name="findResourceIdByScope", query="select r.id from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"),
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
index c938afe..0c82dc0 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
@@ -237,11 +237,17 @@ public class JPAResourceStore implements ResourceStore {
 
     @Override
     public Resource findByName(String name, String resourceServerId) {
+        return findByName(name, resourceServerId, resourceServerId);
+    }
+
+    @Override
+    public Resource findByName(String name, String ownerId, String resourceServerId) {
         TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByName", String.class);
 
         query.setFlushMode(FlushModeType.COMMIT);
         query.setParameter("serverId", resourceServerId);
         query.setParameter("name", name);
+        query.setParameter("ownerId", ownerId);
 
         try {
             String id = query.getSingleResult();
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
index 0f58741..88c898b 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
@@ -285,7 +285,7 @@ public final class AuthorizationProvider implements Provider {
                         }
 
                         if (resource == null) {
-                            throw new RuntimeException("Resource [" + id + "] does not exist");
+                            throw new RuntimeException("Resource [" + id + "] does not exist or is not owned by the resource server.");
                         }
 
                         return resource.getId();
@@ -460,6 +460,11 @@ public final class AuthorizationProvider implements Provider {
             }
 
             @Override
+            public Resource findByName(String name, String ownerId, String resourceServerId) {
+                return delegate.findByName(name, ownerId, resourceServerId);
+            }
+
+            @Override
             public List<Resource> findByType(String type, String resourceServerId) {
                 return delegate.findByType(type, resourceServerId);
             }
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java
index 74a2e07..cbf23cb 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java
@@ -18,11 +18,26 @@
 
 package org.keycloak.authorization.policy.evaluation;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.Decision;
 import org.keycloak.authorization.Decision.Effect;
 import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RoleUtils;
 import org.keycloak.representations.idm.authorization.Logic;
 
 /**
@@ -36,6 +51,7 @@ public class DefaultEvaluation implements Evaluation {
     private final Policy policy;
     private final Policy parentPolicy;
     private final AuthorizationProvider authorizationProvider;
+    private final Realm realm;
     private Effect effect;
 
     public DefaultEvaluation(ResourcePermission permission, EvaluationContext executionContext, Policy parentPolicy, Policy policy, Decision decision, AuthorizationProvider authorizationProvider) {
@@ -45,6 +61,7 @@ public class DefaultEvaluation implements Evaluation {
         this.policy = policy;
         this.decision = decision;
         this.authorizationProvider = authorizationProvider;
+        this.realm = createRealm();
     }
 
     @Override
@@ -85,6 +102,11 @@ public class DefaultEvaluation implements Evaluation {
     }
 
     @Override
+    public Realm getRealm() {
+        return realm;
+    }
+
+    @Override
     public AuthorizationProvider getAuthorizationProvider() {
         return authorizationProvider;
     }
@@ -102,4 +124,128 @@ public class DefaultEvaluation implements Evaluation {
             deny();
         }
     }
+
+    private Realm createRealm() {
+        return new Realm() {
+
+            @Override
+            public boolean isUserInGroup(String id, String groupId, boolean checkParent) {
+                KeycloakSession session = authorizationProvider.getKeycloakSession();
+                UserModel user = getUser(id, session);
+
+                if (Objects.isNull(user)) {
+                    return false;
+                }
+
+                RealmModel realm = session.getContext().getRealm();
+                GroupModel group = KeycloakModelUtils.findGroupByPath(realm, groupId);
+
+                if (Objects.isNull(group)) {
+                    return false;
+                }
+
+                if (checkParent) {
+                    return RoleUtils.isMember(user.getGroups(), group);
+                }
+
+                return user.isMemberOf(group);
+            }
+
+            private UserModel getUser(String id, KeycloakSession session) {
+                RealmModel realm = session.getContext().getRealm();
+                UserModel user = session.users().getUserById(id, realm);
+
+                if (Objects.isNull(user)) {
+                    user = session.users().getUserByUsername(id, realm);
+
+                    if (Objects.isNull(user)) {
+                        user = session.users().getUserByEmail(id, realm);
+                    }
+                }
+
+                return user;
+            }
+
+            @Override
+            public boolean isUserInRealmRole(String id, String roleName) {
+                KeycloakSession session = authorizationProvider.getKeycloakSession();
+                UserModel user = getUser(id, session);
+
+                if (Objects.isNull(user)) {
+                    return false;
+                }
+
+                Set<RoleModel> roleMappings = user.getRoleMappings().stream()
+                        .filter(role -> !role.isClientRole())
+                        .collect(Collectors.toSet());
+
+                return RoleUtils.hasRole(roleMappings, session.getContext().getRealm().getRole(roleName));
+            }
+
+            @Override
+            public boolean isUserInClientRole(String id, String clientId, String roleName) {
+                KeycloakSession session = authorizationProvider.getKeycloakSession();
+                RealmModel realm = session.getContext().getRealm();
+                UserModel user = getUser(id, session);
+
+                if (Objects.isNull(user)) {
+                    return false;
+                }
+
+                Set<RoleModel> roleMappings = user.getRoleMappings().stream()
+                        .filter(role -> role.isClientRole() && ClientModel.class.cast(role.getContainer()).getClientId().equals(clientId))
+                        .collect(Collectors.toSet());
+
+                if (roleMappings.isEmpty()) {
+                    return false;
+                }
+
+                RoleModel role = realm.getClientById(ClientModel.class.cast(roleMappings.iterator().next().getContainer()).getId()).getRole(roleName);
+
+                if (Objects.isNull(role)) {
+                    return false;
+                }
+
+                return RoleUtils.hasRole(roleMappings, role);
+            }
+
+            @Override
+            public boolean isGroupInRole(String id, String role) {
+                KeycloakSession session = authorizationProvider.getKeycloakSession();
+                RealmModel realm = session.getContext().getRealm();
+                GroupModel group = KeycloakModelUtils.findGroupByPath(realm, id);
+
+                return RoleUtils.hasRoleFromGroup(group, realm.getRole(role), false);
+            }
+
+            @Override
+            public List<String> getUserRealmRoles(String id) {
+                return getUser(id, authorizationProvider.getKeycloakSession()).getRoleMappings().stream()
+                        .filter(role -> !role.isClientRole())
+                        .map(RoleModel::getName)
+                        .collect(Collectors.toList());
+            }
+
+            @Override
+            public List<String> getUserClientRoles(String id, String clientId) {
+                return getUser(id, authorizationProvider.getKeycloakSession()).getRoleMappings().stream()
+                        .filter(role -> role.isClientRole())
+                        .map(RoleModel::getName)
+                        .collect(Collectors.toList());
+            }
+
+            @Override
+            public List<String> getUserGroups(String id) {
+                return getUser(id, authorizationProvider.getKeycloakSession()).getGroups().stream()
+                        .map(ModelToRepresentation::buildGroupPath)
+                        .collect(Collectors.toList());
+            }
+
+            @Override
+            public Map<String, List<String>> getUserAttributes(String id) {
+                Map<String, List<String>> attributes = getUser(id, authorizationProvider.getKeycloakSession()).getAttributes();
+                return attributes;
+            }
+        };
+    }
 }
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
index 4ac0264..7fd6566 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
@@ -51,6 +51,13 @@ public interface Evaluation {
      */
     Policy getPolicy();
 
+    /**
+     * Returns a {@link Realm} that can be used by policies to query information.
+     *
+     * @return a {@link Realm} instance
+     */
+    Realm getRealm();
+
     AuthorizationProvider getAuthorizationProvider();
 
     /**
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java
index 708f7e1..df7c705 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java
@@ -117,7 +117,7 @@ public class PermissionTicketAwareDecisionResultCollector extends DecisionResult
                     Resource resource = resourceStore.findById(permission.getResourceId(), resourceServer.getId());
 
                     if (resource == null) {
-                        resource = resourceStore.findByName(permission.getResourceId(), resourceServer.getId());
+                        resource = resourceStore.findByName(permission.getResourceId(), identity.getId(), resourceServer.getId());
                     }
 
                     if (!resource.isOwnerManagedAccess() || resource.getOwner().equals(identity.getId()) || resource.getOwner().equals(resourceServer.getId())) {
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Realm.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Realm.java
new file mode 100644
index 0000000..b5d5dbb
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Realm.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.evaluation;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This interface provides methods to query information from a realm.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Realm {
+
+    /**
+     * <p>Checks whether or not a user with the given <code>id</code> is a member of the given <code>group</code>.
+     *
+     * <p>This method will also consider memberships where the user is a member of any child group of the given <code>group</code>.
+     * For instance, if user is member of <code>/Group A/Group B</code> and this method is checking if user is a member of <code>/Group A</code>
+     * the result will be <code>true</code> given that the user is a member of a child group of <code>/Group A</code>.
+     *
+     * @param id the user id. It can be the id, username or email
+     * @param group the group path. For instance, /Group A/Group B.
+     * @return true if user is a member of the given group. Otherwise returns false.
+     */
+    default boolean isUserInGroup(String id, String group) {
+        return isUserInGroup(id, group, true);
+    }
+
+    /**
+     * Checks whether or not a user with the given <code>id</code> is a member of the given <code>group</code>.
+     *
+     * @param id the user id. It can be the id, username or email
+     * @param group the group path. For instance, /Group A/Group B.
+     * @param checkParent if true, this method returns true even though the user is not directly associated with the given group but a member of any child of the group.
+     * @return true if user is a member of the given group. Otherwise returns false.
+     */
+    boolean isUserInGroup(String id, String group, boolean checkParent);
+
+    /**
+     * Checks whether or not a user with the given <code>id</code> is granted with the given realm <code>role</code>.
+     *
+     * @param id the user id. It can be the id, username or email
+     * @param role the role name
+     * @return true if the user is granted with the role. Otherwise, false.
+     */
+    boolean isUserInRealmRole(String id, String role);
+
+    /**
+     * Checks whether or not a user with the given <code>id</code> is granted with the given client <code>role</code>.
+     *
+     * @param id the user id. It can be the id, username or email
+     * @param clientId the client id
+     * @param role the role name
+     * @return true if the user is granted with the role. Otherwise, false.
+     */
+    boolean isUserInClientRole(String id, String clientId, String role);
+
+    /**
+     * Checks whether or not a <code>group</code> is granted with the given realm <code>role</code>.
+     *
+     * @param group the group path. For instance, /Group A/Group B.
+     * @param role the role name
+     * @return true if the group is granted with the role. Otherwise, false.
+     */
+    boolean isGroupInRole(String group, String role);
+
+    /**
+     * Returns all realm roles granted for a user with the given <code>id</code>.
+     *
+     * @param id the user id. It can be the id, username or email
+     * @return the roles granted to the user
+     */
+    List<String> getUserRealmRoles(String id);
+
+    /**
+     * Returns all client roles granted for a user with the given <code>id</code>.
+     *
+     * @param id the user id. It can be the id, username or email
+     * @param clientId the client id
+     * @return the roles granted to the user
+     */
+    List<String> getUserClientRoles(String id, String clientId);
+
+    /**
+     * Returns all groups which the user with the given <code>id</code> is a member.
+     *
+     * @param id the user id. It can be the id, username or email
+     * @return the groups which the user is a member
+     */
+    List<String> getUserGroups(String id);
+
+    /**
+     * Returns all attributes associated with the a user with the given <code>id</code>.
+     *
+     * @param id the user id. It can be the id, username or email
+     * @return a map with the attributes associated with the user
+     */
+    Map<String, List<String>> getUserAttributes(String id);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
index 9a2ac51..fd6f85c 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
@@ -97,7 +97,7 @@ public interface ResourceStore {
     List<Resource> findByScope(List<String> id, String resourceServerId);
 
     /**
-     * Find a {@link Resource} by its name.
+     * Find a {@link Resource} by its name where the owner is the resource server itself.
      *
      * @param name the name of the resource
      * @param resourceServerId the identifier of the resource server
@@ -106,6 +106,16 @@ public interface ResourceStore {
     Resource findByName(String name, String resourceServerId);
 
     /**
+     * Find a {@link Resource} by its name where the owner is the given <code>ownerId</code>.
+     *
+     * @param name the name of the resource
+     * @param ownerId the owner id
+     * @param resourceServerId the identifier of the resource server
+     * @return a resource with the given name
+     */
+    Resource findByName(String name, String ownerId, String resourceServerId);
+
+    /**
      * Finds all {@link Resource} with the given type.
      *
      * @param type the type of the resource
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index c738b81..7324913 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -2275,7 +2275,7 @@ public class RepresentationToModel {
                     if (resource == null) {
                         resource = storeFactory.getResourceStore().findByName(resourceId, policy.getResourceServer().getId());
                         if (resource == null) {
-                            throw new RuntimeException("Resource with id or name [" + resourceId + "] does not exist");
+                            throw new RuntimeException("Resource with id or name [" + resourceId + "] does not exist or is not owned by the resource server");
                         }
                     }
 
@@ -2303,28 +2303,6 @@ public class RepresentationToModel {
 
     public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
         ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
-        Resource existing;
-
-        if (resource.getId() != null) {
-            existing = resourceStore.findById(resource.getId(), resourceServer.getId());
-        } else {
-            existing = resourceStore.findByName(resource.getName(), resourceServer.getId());
-        }
-
-        if (existing != null) {
-            existing.setName(resource.getName());
-            existing.setDisplayName(resource.getDisplayName());
-            existing.setType(resource.getType());
-            existing.setUri(resource.getUri());
-            existing.setIconUri(resource.getIconUri());
-            existing.setOwnerManagedAccess(Boolean.TRUE.equals(resource.getOwnerManagedAccess()));
-            existing.updateScopes(resource.getScopes().stream()
-                    .map((ScopeRepresentation scope) -> toModel(scope, resourceServer, authorization))
-                    .collect(Collectors.toSet()));
-
-            return existing;
-        }
-
         ResourceOwnerRepresentation owner = resource.getOwner();
 
         if (owner == null) {
@@ -2338,12 +2316,6 @@ public class RepresentationToModel {
             throw new RuntimeException("No owner specified for resource [" + resource.getName() + "].");
         }
 
-        ClientModel clientModel = authorization.getRealm().getClientById(resourceServer.getId());
-
-        if (ownerId.equals(clientModel.getClientId())) {
-            ownerId = resourceServer.getId();
-        }
-
         if (!resourceServer.getId().equals(ownerId)) {
             RealmModel realm = authorization.getRealm();
             KeycloakSession keycloakSession = authorization.getKeycloakSession();
@@ -2361,6 +2333,28 @@ public class RepresentationToModel {
             ownerId = ownerModel.getId();
         }
 
+        Resource existing;
+
+        if (resource.getId() != null) {
+            existing = resourceStore.findById(resource.getId(), resourceServer.getId());
+        } else {
+            existing = resourceStore.findByName(resource.getName(), ownerId, resourceServer.getId());
+        }
+
+        if (existing != null) {
+            existing.setName(resource.getName());
+            existing.setDisplayName(resource.getDisplayName());
+            existing.setType(resource.getType());
+            existing.setUri(resource.getUri());
+            existing.setIconUri(resource.getIconUri());
+            existing.setOwnerManagedAccess(Boolean.TRUE.equals(resource.getOwnerManagedAccess()));
+            existing.updateScopes(resource.getScopes().stream()
+                    .map((ScopeRepresentation scope) -> toModel(scope, resourceServer, authorization))
+                    .collect(Collectors.toSet()));
+
+            return existing;
+        }
+
         Resource model = resourceStore.create(resource.getName(), resourceServer, ownerId);
 
         model.setDisplayName(resource.getDisplayName());

services/pom.xml 43(+22 -21)

diff --git a/services/pom.xml b/services/pom.xml
index 77e15c7..1f212e6 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -205,27 +205,6 @@
         <profile>
             <id>jboss-release</id>
 
-            <repositories>
-                <repository>
-                    <snapshots>
-                        <enabled>false</enabled>
-                    </snapshots>
-                    <id>central</id>
-                    <name>bintray</name>
-                    <url>https://jcenter.bintray.com</url>
-                </repository>
-            </repositories>
-            <pluginRepositories>
-                <pluginRepository>
-                    <snapshots>
-                        <enabled>false</enabled>
-                    </snapshots>
-                    <id>central</id>
-                    <name>bintray</name>
-                    <url>https://jcenter.bintray.com</url>
-                </pluginRepository>
-            </pluginRepositories>
-
             <build>
                 <plugins>
                     <plugin>
@@ -289,6 +268,28 @@
                         <artifactId>swagger2markup-maven-plugin</artifactId>
                         <version>1.1.0</version>
 
+                        <!-- Replace the dependencies that aren't in Maven Central -->
+                        <dependencies>
+                            <dependency>
+                                <groupId>ca.szc.thirdparty.nl.jworks.markdown_to_asciidoc</groupId>
+                                <artifactId>markdown_to_asciidoc</artifactId>
+                                <!-- Keep in sync with markup-document-builder's dependency -->
+                                <version>1.0</version>
+                            </dependency>
+                            <dependency>
+                                <groupId>io.github.swagger2markup</groupId>
+                                <artifactId>swagger2markup</artifactId>
+                                <!-- Keep in sync with swagger2markup-maven-plugin's dependency -->
+                                <version>1.1.0</version>
+                                <exclusions>
+                                    <exclusion>
+                                        <groupId>nl.jworks.markdown_to_asciidoc</groupId>
+                                        <artifactId>markdown_to_asciidoc</artifactId>
+                                    </exclusion>
+                                </exclusions>
+                            </dependency>
+                        </dependencies>
+
                         <executions>
                             <execution>
                                 <id>gen-asciidoc</id>
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
index d5c6b60..742454e 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
@@ -57,6 +57,7 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
     public static final String MAPPING_SOURCE_SELECTION = "x509-cert-auth.mapping-source-selection";
     public static final String MAPPING_SOURCE_CERT_SUBJECTDN = "Match SubjectDN using regular expression";
     public static final String MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL = "Subject's e-mail";
+    public static final String MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL = "Subject's Alternative Name E-mail";
     public static final String MAPPING_SOURCE_CERT_SUBJECTDN_CN = "Subject's Common Name";
     public static final String MAPPING_SOURCE_CERT_ISSUERDN = "Match IssuerDN using regular expression";
     public static final String MAPPING_SOURCE_CERT_ISSUERDN_EMAIL = "Issuer's e-mail";
@@ -146,6 +147,9 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
                             .either(UserIdentityExtractor.getX500NameExtractor(BCStyle.EmailAddress, subject))
                             .or(UserIdentityExtractor.getX500NameExtractor(BCStyle.E, subject));
                     break;
+                case SUBJECTALTNAME_EMAIL:
+                    extractor = UserIdentityExtractor.getSubjectAltNameExtractor(1);
+                    break;
                 case ISSUERDN_CN:
                     extractor = UserIdentityExtractor.getX500NameExtractor(BCStyle.CN, issuer);
                     break;
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
index 03601e2..29af551 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
@@ -43,6 +43,7 @@ import static org.keycloak.authentication.authenticators.x509.AbstractX509Client
 import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_ISSUERDN_CN;
 import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_ISSUERDN_EMAIL;
 import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SERIALNUMBER;
+import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL;
 import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTDN;
 import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTDN_CN;
 import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL;
@@ -68,6 +69,7 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
     private static final String[] mappingSources = {
             MAPPING_SOURCE_CERT_SUBJECTDN,
             MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL,
+            MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL,
             MAPPING_SOURCE_CERT_SUBJECTDN_CN,
             MAPPING_SOURCE_CERT_ISSUERDN,
             MAPPING_SOURCE_CERT_ISSUERDN_EMAIL,
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
index ef29aec..881fdb7 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
@@ -25,7 +25,11 @@ import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x500.style.IETFUtils;
 import org.keycloak.services.ServicesLogger;
 
+import java.security.cert.CertificateParsingException;
 import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
 import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -92,6 +96,52 @@ public abstract class UserIdentityExtractor {
         }
     }
 
+    /**
+     * Extracts the subject identifier from the subjectAltName extension.
+     */
+    static class SubjectAltNameExtractor extends UserIdentityExtractor {
+
+        private final int generalName;
+
+        /**
+         * Creates a new instance
+         *
+         * @param generalName an integer representing the general name. See {@link X509Certificate#getSubjectAlternativeNames()}
+         */
+        SubjectAltNameExtractor(int generalName) {
+            this.generalName = generalName;
+        }
+
+        @Override
+        public Object extractUserIdentity(X509Certificate[] certs) {
+            if (certs == null || certs.length == 0) {
+                throw new IllegalArgumentException();
+            }
+
+            try {
+                Collection<List<?>> subjectAlternativeNames = certs[0].getSubjectAlternativeNames();
+
+                if (subjectAlternativeNames == null) {
+                    return null;
+                }
+
+                Iterator<List<?>> iterator = subjectAlternativeNames.iterator();
+
+                while (iterator.hasNext()) {
+                    List<?> next = iterator.next();
+
+                    if (Integer.class.cast(next.get(0)) == generalName) {
+                        return next.get(1);
+                    }
+                }
+            } catch (CertificateParsingException cause) {
+                logger.errorf(cause, "Failed to obtain identity from subjectAltName extension");
+            }
+
+            return null;
+        }
+    }
+
     static class PatternMatcher extends UserIdentityExtractor {
         private final String _pattern;
         private final Function<X509Certificate[],String> _f;
@@ -143,6 +193,16 @@ public abstract class UserIdentityExtractor {
         return new X500NameRDNExtractor(identifier, x500Name);
     }
 
+    /**
+     * Obtains the subjectAltName given a <code>generalName</code>.
+     *
+     * @param generalName an integer representing the general name. See {@link X509Certificate#getSubjectAlternativeNames()}
+     * @return the value from the subjectAltName extension
+     */
+    public static SubjectAltNameExtractor getSubjectAltNameExtractor(int generalName) {
+        return new SubjectAltNameExtractor(generalName);
+    }
+
     public static OrBuilder either(UserIdentityExtractor extractor) {
         return new OrBuilder(extractor);
     }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
index 87c60b4..a738f42 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
@@ -60,6 +60,7 @@ public class X509AuthenticatorConfigModel extends AuthenticatorConfigModel {
         ISSUERDN(MAPPING_SOURCE_CERT_ISSUERDN),
         SUBJECTDN_CN(MAPPING_SOURCE_CERT_SUBJECTDN_CN),
         SUBJECTDN_EMAIL(MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL),
+        SUBJECTALTNAME_EMAIL(MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL),
         SUBJECTDN(MAPPING_SOURCE_CERT_SUBJECTDN);
 
         private String name;
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
index 0e4f911..04c9d74 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
@@ -118,7 +118,6 @@ public class ResourceSetService {
     public Response create(ResourceRepresentation resource, Function<Resource, ?> toRepresentation) {
         requireManage();
         StoreFactory storeFactory = this.authorization.getStoreFactory();
-        Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), this.resourceServer.getId());
         ResourceOwnerRepresentation owner = resource.getOwner();
 
         if (owner == null) {
@@ -132,7 +131,9 @@ public class ResourceSetService {
             return ErrorResponse.error("You must specify the resource owner.", Status.BAD_REQUEST);
         }
 
-        if (existingResource != null && existingResource.getOwner().equals(ownerId)) {
+        Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), ownerId, this.resourceServer.getId());
+
+        if (existingResource != null) {
             return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists.");
         }
 
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
index a8075a0..989d228 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -172,13 +172,13 @@ public class AuthorizationTokenService {
 
     private List<Result> evaluatePermissions(AuthorizationRequest authorizationRequest, PermissionTicketToken ticket, ResourceServer resourceServer, KeycloakEvaluationContext evaluationContext, KeycloakIdentity identity) {
         return authorization.evaluators()
-                .from(createPermissions(ticket, authorizationRequest, resourceServer, authorization), evaluationContext)
+                .from(createPermissions(ticket, authorizationRequest, resourceServer, identity, authorization), evaluationContext)
                 .evaluate();
     }
 
     private List<Result> evaluateUserManagedPermissions(AuthorizationRequest request, PermissionTicketToken ticket, ResourceServer resourceServer, KeycloakEvaluationContext evaluationContext, KeycloakIdentity identity) {
         return authorization.evaluators()
-                .from(createPermissions(ticket, request, resourceServer, authorization), evaluationContext)
+                .from(createPermissions(ticket, request, resourceServer, identity, authorization), evaluationContext)
                 .evaluate(new PermissionTicketAwareDecisionResultCollector(request, ticket, identity, resourceServer, authorization)).results();
     }
 
@@ -276,7 +276,7 @@ public class AuthorizationTokenService {
         return evaluationContextProvider.apply(authorizationRequest, authorization);
     }
 
-    private List<ResourcePermission> createPermissions(PermissionTicketToken ticket, AuthorizationRequest request, ResourceServer resourceServer, AuthorizationProvider authorization) {
+    private List<ResourcePermission> createPermissions(PermissionTicketToken ticket, AuthorizationRequest request, ResourceServer resourceServer, KeycloakIdentity identity, AuthorizationProvider authorization) {
         StoreFactory storeFactory = authorization.getStoreFactory();
         Map<String, Set<String>> permissionsToEvaluate = new LinkedHashMap<>();
         ResourceStore resourceStore = storeFactory.getResourceStore();
@@ -294,17 +294,31 @@ public class AuthorizationTokenService {
                 requestedScopes = new HashSet<>();
             }
 
-            Resource existingResource = null;
+            List<Resource> existingResources = new ArrayList<>();
 
             if (requestedResource.getResourceId() != null) {
-                existingResource = resourceStore.findById(requestedResource.getResourceId(), resourceServer.getId());
+                Resource resource = resourceStore.findById(requestedResource.getResourceId(), resourceServer.getId());
 
-                if (existingResource == null) {
-                    existingResource = resourceStore.findByName(requestedResource.getResourceId(), resourceServer.getId());
+                if (resource != null) {
+                    existingResources.add(resource);
+                } else {
+                    Resource ownerResource = resourceStore.findByName(requestedResource.getResourceId(), identity.getId(), resourceServer.getId());
+
+                    if (ownerResource != null) {
+                        existingResources.add(ownerResource);
+                    }
+
+                    if (!identity.isResourceServer()) {
+                        Resource serverResource = resourceStore.findByName(requestedResource.getResourceId(), resourceServer.getId());
+
+                        if (serverResource != null) {
+                            existingResources.add(serverResource);
+                        }
+                    }
                 }
             }
 
-            if (existingResource == null && (requestedScopes == null || requestedScopes.isEmpty())) {
+            if (existingResources.isEmpty() && (requestedScopes == null || requestedScopes.isEmpty())) {
                 throw new CorsErrorResponseException(cors, "invalid_resource", "Resource with id [" + requestedResource.getResourceId() + "] does not exist.", Status.FORBIDDEN);
             }
 
@@ -314,18 +328,20 @@ public class AuthorizationTokenService {
                 requestedScopes.addAll(Arrays.asList(clientAdditionalScopes.split(" ")));
             }
 
-            if (existingResource != null) {
-                Set<String> scopes = permissionsToEvaluate.get(existingResource.getId());
+            if (!existingResources.isEmpty()) {
+                for (Resource resource : existingResources) {
+                    Set<String> scopes = permissionsToEvaluate.get(resource.getId());
 
-                if (scopes == null) {
-                    scopes = new HashSet<>();
-                    permissionsToEvaluate.put(existingResource.getId(), scopes);
-                    if (limit != null) {
-                        limit--;
+                    if (scopes == null) {
+                        scopes = new HashSet<>();
+                        permissionsToEvaluate.put(resource.getId(), scopes);
+                        if (limit != null) {
+                            limit--;
+                        }
                     }
-                }
 
-                scopes.addAll(requestedScopes);
+                    scopes.addAll(requestedScopes);
+                }
             } else {
                 List<Resource> resources = resourceStore.findByScope(new ArrayList<>(requestedScopes), ticket.getAudience()[0]);
 
diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
index 58962b5..b2ea5d4 100644
--- a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
@@ -224,7 +224,7 @@ public class KeycloakIdentity implements Identity {
         return this.accessToken;
     }
 
-    private  boolean isResourceServer() {
+    public boolean isResourceServer() {
         UserModel clientUser = null;
 
         ClientModel clientModel = getTargetClient();
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java b/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java
index 7a8e05e..7dd3496 100644
--- a/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java
@@ -67,41 +67,61 @@ public class AbstractPermissionService {
 
     private List<ResourceRepresentation> verifyRequestedResource(List<PermissionRequest> request) {
         ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
+        List<ResourceRepresentation> requestedResources = new ArrayList<>();
 
-        return request.stream().map(permissionRequest -> {
+        for (PermissionRequest permissionRequest : request) {
             String resourceSetId = permissionRequest.getResourceId();
-            Resource resource = null;
+            List<Resource> resources = new ArrayList<>();
 
             if (resourceSetId == null) {
                 if (permissionRequest.getScopes() == null || permissionRequest.getScopes().isEmpty()) {
                     throw new ErrorResponseException("invalid_resource_id", "Resource id or name not provided.", Response.Status.BAD_REQUEST);
                 }
             } else {
-                resource = resourceStore.findById(resourceSetId, resourceServer.getId());
+                Resource resource = resourceStore.findById(resourceSetId, resourceServer.getId());
 
-                if (resource == null) {
-                    resource = resourceStore.findByName(resourceSetId, this.resourceServer.getId());
+                if (resource != null) {
+                    resources.add(resource);
+                } else {
+                    Resource userResource = resourceStore.findByName(resourceSetId, identity.getId(), this.resourceServer.getId());
+
+                    if (userResource != null) {
+                        resources.add(userResource);
+                    }
+
+                    if (!identity.isResourceServer()) {
+                        Resource serverResource = resourceStore.findByName(resourceSetId, this.resourceServer.getId());
+
+                        if (serverResource != null) {
+                            resources.add(serverResource);
+                        }
+                    }
                 }
 
-                if (resource == null) {
+                if (resources.isEmpty()) {
                     throw new ErrorResponseException("invalid_resource_id", "Resource set with id [" + resourceSetId + "] does not exists in this server.", Response.Status.BAD_REQUEST);
                 }
             }
 
-            Set<ScopeRepresentation> scopes = verifyRequestedScopes(permissionRequest, resource);
+            if (resources.isEmpty()) {
+                requestedResources.add(new ResourceRepresentation(null, verifyRequestedScopes(permissionRequest, null)));
 
-            if (resource != null) {
-                ResourceRepresentation representation = new ResourceRepresentation(resource.getName(), scopes);
+            } else {
+                for (Resource resource : resources) {
+                    Set<ScopeRepresentation> scopes = verifyRequestedScopes(permissionRequest, resource);
 
-                representation.setId(resource.getId());
-                representation.setOwnerManagedAccess(resource.isOwnerManagedAccess());
-                representation.setOwner(new ResourceOwnerRepresentation(resource.getOwner()));
+                    ResourceRepresentation representation = new ResourceRepresentation(resource.getName(), scopes);
 
-                return representation;
+                    representation.setId(resource.getId());
+                    representation.setOwnerManagedAccess(resource.isOwnerManagedAccess());
+                    representation.setOwner(new ResourceOwnerRepresentation(resource.getOwner()));
+
+                    requestedResources.add(representation);
+                }
             }
+        }
 
-            return new ResourceRepresentation(null, scopes);
-        }).collect(Collectors.toList());
+        return requestedResources;
     }
 
     private Set<ScopeRepresentation> verifyRequestedScopes(PermissionRequest request, Resource resource) {
diff --git a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
index a722f8e..ef4cb85 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
@@ -59,6 +59,7 @@ import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import java.io.IOException;
 import java.net.URI;
+import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -315,6 +316,13 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
             uriBuilder.queryParam(OAuth2Constants.PROMPT, prompt);
         }
 
+        String nonce = request.getAuthenticationSession().getClientNote(OIDCLoginProtocol.NONCE_PARAM);
+        if (nonce == null || nonce.isEmpty()) {
+            nonce = UUID.randomUUID().toString();
+            request.getAuthenticationSession().setClientNote(OIDCLoginProtocol.NONCE_PARAM, nonce);
+        }
+        uriBuilder.queryParam(OIDCLoginProtocol.NONCE_PARAM, nonce);
+
         String acr = request.getAuthenticationSession().getClientNote(OAuth2Constants.ACR_VALUES);
         if (acr != null) {
             uriBuilder.queryParam(OAuth2Constants.ACR_VALUES, acr);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java
index 3562ed5..46a11a2 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java
@@ -23,6 +23,7 @@ import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.services.ErrorPageException;
 import org.keycloak.services.ServicesLogger;
@@ -31,6 +32,9 @@ import org.keycloak.services.messages.Messages;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import java.io.InputStream;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST_URI;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -50,6 +54,19 @@ public class AuthorizationEndpointRequestParserProcessor {
                 throw new RuntimeException("Illegal to use both 'request' and 'request_uri' parameters together");
             }
 
+            String requestObjectRequired = OIDCAdvancedConfigWrapper.fromClientModel(client).getRequestObjectRequired();
+
+            if (REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI.equals(requestObjectRequired)
+                    && requestParam == null && requestUriParam == null) {
+                throw new RuntimeException("Client is required to use 'request' or 'request_uri' parameter.");
+            } else if (REQUEST_OBJECT_REQUIRED_REQUEST.equals(requestObjectRequired)
+                    && requestParam == null) {
+                throw new RuntimeException("Client is required to use 'request' parameter.");
+            } else if (REQUEST_OBJECT_REQUIRED_REQUEST_URI.equals(requestObjectRequired)
+                    && requestUriParam == null) {
+                throw new RuntimeException("Client is required to use 'request_uri' parameter.");
+            }
+
             if (requestParam != null) {
                 new AuthzEndpointRequestObjectParser(session, requestParam, client).parseRequest(request);
             } else if (requestUriParam != null) {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java
index 6f4ff75..600214e 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java
@@ -31,6 +31,11 @@ public class OIDCAdvancedConfigWrapper {
     private static final String USER_INFO_RESPONSE_SIGNATURE_ALG = "user.info.response.signature.alg";
 
     private static final String REQUEST_OBJECT_SIGNATURE_ALG = "request.object.signature.alg";
+    
+    private static final String REQUEST_OBJECT_REQUIRED = "request.object.required";
+    public static final String REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI = "request or request_uri";
+    public static final String REQUEST_OBJECT_REQUIRED_REQUEST = "request only";
+    public static final String REQUEST_OBJECT_REQUIRED_REQUEST_URI = "request_uri only";
 
     private static final String JWKS_URL = "jwks.url";
 
@@ -79,6 +84,14 @@ public class OIDCAdvancedConfigWrapper {
         String algStr = alg==null ? null : alg.toString();
         setAttribute(REQUEST_OBJECT_SIGNATURE_ALG, algStr);
     }
+    
+    public String getRequestObjectRequired() {
+        return getAttribute(REQUEST_OBJECT_REQUIRED);
+    }
+    
+    public void setRequestObjectRequired(String requestObjectRequired) {
+        setAttribute(REQUEST_OBJECT_REQUIRED, requestObjectRequired);
+    }
 
     public boolean isUseJwksUrl() {
         String useJwksUrl = getAttribute(USE_JWKS_URL);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 4da336c..56c0022 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -219,7 +219,11 @@ public class OIDCLoginProtocol implements LoginProtocol {
                 if (responseType.hasResponseType(OIDCResponseType.CODE)) {
                     responseBuilder.generateCodeHash(code);
                 }
-
+                
+                // Financial API - Part 2: Read and Write API Security Profile
+                // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+                if (state != null && !state.isEmpty())
+                    responseBuilder.generateStateHash(state);
             }
 
             AccessTokenResponse res = responseBuilder.build();
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 e21f3ad..41b71a7 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -718,6 +718,10 @@ public class TokenManager {
         boolean generateAccessTokenHash = false;
         String codeHash;
 
+        // Financial API - Part 2: Read and Write API Security Profile
+        // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+        String stateHash;
+        
         public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
             this.realm = realm;
             this.client = client;
@@ -819,6 +823,12 @@ public class TokenManager {
             return this;
         }
 
+        // Financial API - Part 2: Read and Write API Security Profile
+        // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+        public AccessTokenResponseBuilder generateStateHash(String state) {
+            stateHash = HashProvider.oidcHash(jwsAlgorithm, state);
+            return this;
+        }
 
         public AccessTokenResponse build() {
             KeyManager.ActiveRsaKey activeRsaKey = session.keys().getActiveRsaKey(realm);
@@ -854,7 +864,11 @@ public class TokenManager {
             if (codeHash != null) {
                 idToken.setCodeHash(codeHash);
             }
-
+            // Financial API - Part 2: Read and Write API Security Profile
+            // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+            if (stateHash != null) {
+                idToken.setStateHash(stateHash);
+            }
             if (idToken != null) {
                 String encodedToken = new JWSBuilder().type(JWT).kid(activeRsaKey.getKid()).jsonContent(idToken).sign(jwsAlgorithm, activeRsaKey.getPrivateKey());
                 res.setIdToken(encodedToken);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index 02063fa..a61dd05 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -32,8 +32,8 @@ import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserManager;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
@@ -573,13 +573,17 @@ public class ClientResource {
 
 
     private void updateClientFromRep(ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException {
+        UserModel serviceAccount = this.session.users().getServiceAccount(client);
         if (TRUE.equals(rep.isServiceAccountsEnabled())) {
-            UserModel serviceAccount = this.session.users().getServiceAccount(client);
-
             if (serviceAccount == null) {
                 new ClientManager(new RealmManager(session)).enableServiceAccount(client);
             }
         }
+        else {
+            if (serviceAccount != null) {
+                new UserManager(session).removeUser(realm, serviceAccount);
+            }
+        }
 
         if (!rep.getClientId().equals(client.getClientId())) {
             new ClientManager(new RealmManager(session)).clientIdChanged(client, rep.getClientId());
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli b/testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli
index fd08666..2e50470 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli
@@ -139,4 +139,8 @@ echo *** Enable debug logging ***
 echo *** Update undertow subsystem ***
 /subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)
 
+echo *** Update keycloak-server subsystem, infinispan remoteStoreSecurity ***
+/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:map-put(name=properties,key=remoteStoreSecurityEnabled,value=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled:true})
+
+
 echo **** End ****
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore
index 5253c8f..d461868 100644
Binary files a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore and b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore differ
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/README.md b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/README.md
new file mode 100644
index 0000000..9766cc3
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/README.md
@@ -0,0 +1,8 @@
+# Keycloak Arquillian Integration Testsuite
+
+This directory contains a OpenSSL CA and Intermediate CA that can be used to manage certificates.
+
+## Passwords
+
+Passwords for any key file is `password`.
+
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/ca.cert.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/ca.cert.pem
new file mode 100644
index 0000000..123bef7
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/ca.cert.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+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
+SCc=
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user@localhost.key.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user@localhost.key.pem
new file mode 100644
index 0000000..20ff9ff
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user@localhost.key.pem
@@ -0,0 +1,54 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,58507FBFA90F44D96D42E8ED4989032F
+
+eO/DUxz7PGUmyv6Nu89tWvad4O2Jzdr6kNCMsRcaG1JFJsMdGUNtuXjKyEaIKo9B
+MLXAoFgtyW4t0TozNVzsS8mSwkU9eOP+cAGLReoHZ8C+w5y+Dm7Kuc37X+HF0HCL
+4UkfNGKwgVJuXbVFVTTRVypB0Ul9Q2s43iN0YUfsYK333FHdDHxYyk7X+zvbposO
+Q33oFsa0D4Ga2VdE8FQX5pDBqPOjXt8a3LaZxi5r8pZDRY+mcE04qnZLdUk6jCeQ
+u4zHjsn/F+aW+EhAHH9vAwHLJ7lQOBtsdGxj2QXUAnU3LnRs2XxvYtZbxkG/p4sb
+FCAP57bBxmkL51RJTM4fgnq/b1JRtGwS1kRbHSiKTnrDO8JHcmILKSoIUG9IcwNp
+SFcKVZiabEdNSAiY9J+nvZMR8d946SqAQ/kA2Z7WH/6pbs4pd0ODIpYbNYwUfPcP
+51tQI/fna2fyvGA0xxr5MUi3Ua8kp9KmoZaX+ghjwh8QLa82mcvOjbYaV6c2OT4m
+92Eq7Si+u82fq2l5TjmKXLT5dwAUqZU1GnbG2Qd7/HW2h7PFIuReITL9UZhbCMoi
+zOSz3wKniP/npE+I4+hYTRxKaV2mkAd1FC4+QhSZbmupf3WOxbtaJP6V8gd4BgRQ
+O6mN9BvXYihSWyn7zQ/4MuGq5/k+XmTsxhfPZ7KW7DyeDGdl7qTcW5I7k+i6Lnh6
+YozNJn+CVQnZ67x4OhkQ9GQSBkEXudGurzWOJ3xNHOMtAGfQZRjHepcf1TeRN8C1
+voyY0Yx4V95XfbCMzbQckxhDigHJqCBk0bewp0LYXbn0traawZXNJ9nZHDFMyuX9
+Oztjx5cFdH/kxSjy0Qquzy9rtEzw72CnBw/AisaGMkMaxQWP92n0hav5XSKg5eD3
+OD42fsFWvbTN12kFXETDeQGuSJoJ3X2R9UnG2GL1Uc4lEFOu7LVpQX1hVi0qJjsv
+NqFO/4pbB+IpwwHV/6Nh7hwBXQVXKcGq3fq9+iCWk4hmZLutTSrsdsLWyqxF+r+1
+a3mk2nZgpTVkmfNsOf7vY1R4fWkUu7M7Pb0R0eQ9vG8w7Aodym6snkxdZBwl09TM
+YpxofsvgVGcteZWK7hgESODpBklZstNXOIk4hsDhm8+PPfWuOndBEkocAf0D/4OE
+lPGcdG9gTc8HOiJLtK8QSJUbtfauJHqp9Dzkc3qNZuSTwwCvk4v2oYV7FrCzZfcC
+yPgN2AhOx8EDT3vx2IV62dbHeamWlT+hpdCIiEXnyL5MVBvO3Td+g3BM+RRVSmaB
+ZBgfZaFjlZvDDeqH8eOGNoKN06tGdpxeGJaPr5G3ksrmupBVB1Gay+T98Kux4zAk
+fw0oFPDEyRiup+iOXpltRtP7d3SH7ngjapm6aDBs2weWrnLrcjZx5iyOed8z8zWG
+Ygmar31qn0qMUf/8HZb4c3DYkc1mjpKZLQnyouP82p++1VTN8S27Kf06eTob5zYa
+pWhCDHPWA8FFNF9d1zgSTBLEFawryM59rLJteg7G7yiSN43OBk7THNI2OwK8y2Mv
+KvwMoyStvMbiMn4qVR8mcnLrAYUd2RhuDGX3NOExI+9EBSGpwUP22I/nQ9HRlJ9D
+OoKaTIdqv0twC3QYIbYf6RUngD2Yzo8ie9Ys31dZqJidSRj9xnpkb8Xe4S5J2Sxm
+HP7VJsjjlPH9X+Q+xRWqwvzPi/hDBozo5GR1wrLGOVTRSYsXHjrULu+ael+65m+m
+VXg8Ufzl1j/8KttWjvHOi3RJuusOx8Z6U3E/9YoVCqyuR3rXX7ILHq6UrOLPmLhg
+cOyZy3LJXH2MpLbfhVQ6C5xKUJLQm88FBzdfKTt5aSCHzGa0nmT+qzu+x/s4B37H
+hk9/B0W6hUf8TCy8YYRx7vK6IKpo4qVG3R0n/brtWtw5fYCYHna1qPknQWzROUeK
+2sLW1Xv7Tk1koGcDs4Xv6p3jVCgAYE3DsubqGu7y9j49t9D08IukOMbtY6tc5+b6
+zIrZfz8+XpdM9BmQ+5N5yVv2Ut0t7SGoEQ+pHOwsBu2H2dcW+DdfwyCk7izC0eUR
+Fkv//R+uTaX4g3WSI3++ghDtQlcRf0nFn3c3uCK4HSP2E6doPQuuguKXXnJ+syDD
+rsUZUV0Ia8X8ZCLkza7WfFgoJ2hXe6rehU7YLnvBekCMu0S99/a/oJ3t/JJFB0LF
+5aw9nSlunrcCce9umPwKxc2pMcrIEAAjmmUhXza3LgHJsDiYYSDDo2e1Cbb5j61s
+qCbFxB+WFYc2rRnzK/CLIDhIayWcwyelHAelpQOQ+gReh7ZZSSu5c0Rl9brTZ9tN
+HfMPY5/6eBbASXxA9BStFbasLnlOARojkRgEAMOMv4ZyN4gn949Dd3nwC4gr9f++
+IjqV/YgQOKtL4rOMgvLvb5Y0rhDFOiXTdpZBqhk/6bZo1T2j4ts72FdkAmr2u5gp
+VxVyLv8L/KJv8jKqGbqJeMntarl30wfq4SRNe5te81DbSWrUGaQQyYqLL0/ixL2F
+E6O+0bajYmrz45ZGhJqXJRxnlwyDWL1kPy+f8IlItyXp72WqHqKb/IyImvHgxnnm
+IDv06cjX1LvX+fO3B2/9AveksSqnifrMBRjtFhRxTHdLEt9E1kSOJMb4tOlm/QpI
+UQV0HkQRsUE3F6N7OEmfuA88jwiNRTSjl6WbFQ0O01lKFeKmy4cPJfnSOvHNL34Z
+zztSboe9Red6qXzkR1mjh8BO/5Nu2ihlk8spqxNFUoPteUU57KITanXr63IudaSX
+hDA7viBAqcmjPy/j4YY0UVvvWBCqIK0ejcEghxHJak/n3qpiSm0mYMMubi51O5UT
+rxzZ9aqVfw4zmmZqrh+UIAwHJRpQw+zmXIN1h7pdTR1JGuSqStNgSgL53FoX2v9K
+I0QQ6RbGJ7Yleb4P8DUHkaY9ljARsioVdbmzQgYDpt45KG9iFeREadvA0WpuapKE
+/WePOmKMJ+qhnvENPSLLrf5ssho95GWf/6pGEV4PmMLanQ5iGV48wLXMtbQ/ud9N
+qA7XQd2Vb4fNEVQ1aNdXg1gjB3QYyJoB0/exCOm/xLrewfd7zlXk8BERXwV1yQ5f
+tYumN2X4RS2+Y0s9K6ujwEkYi7HUph6vPuq3il4DcSNFj8Wop/f6AAXSml3mqxYd
+-----END RSA PRIVATE KEY-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-san-email@localhost.cert.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-san-email@localhost.cert.pem
new file mode 100644
index 0000000..4a00a12
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-san-email@localhost.cert.pem
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt
new file mode 100644
index 0000000..6976f7c
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt
@@ -0,0 +1 @@
+V	450708195701Z		1000	unknown	/C=US/ST=MA/O=Red Hat/OU=Keycloak/CN=Keycloak Intermediate CA/emailAddress=contact@keycloak.org
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr
new file mode 100644
index 0000000..8f7e63a
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/1 b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/1
new file mode 100644
index 0000000..b596754
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/1
@@ -0,0 +1,131 @@
+# OpenSSL root CA configuration file.
+
+[ ca ]
+# `man ca`
+default_ca = Keycloak
+
+[ Keycloak ]
+# Directory and file locations.
+dir               = ./
+certs             = $dir/certs
+crl_dir           = $dir/crl
+new_certs_dir     = $dir/newcerts
+database          = $dir/index.txt
+serial            = $dir/serial
+RANDFILE          = $dir/private/.rand
+
+# The root key and root certificate.
+private_key       = $dir/private/ca.key.pem
+certificate       = $dir/certs/ca.cert.pem
+
+# For certificate revocation lists.
+crlnumber         = $dir/crlnumber
+crl               = $dir/crl/ca.crl.pem
+crl_extensions    = crl_ext
+default_crl_days  = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md        = sha256
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_strict
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName             = match
+stateOrProvinceName     = match
+organizationName        = match
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits        = 2048
+distinguished_name  = req_distinguished_name
+string_mask         = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md          = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions     = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName                     = Country Name (2 letter code)
+stateOrProvinceName             = State or Province Name
+localityName                    = Locality Name
+0.organizationName              = Organization Name
+organizationalUnitName          = Organizational Unit Name
+commonName                      = Common Name
+emailAddress                    = Email Address
+
+# Optionally, specify some defaults.
+countryName_default             = US
+stateOrProvinceName_default     = MA
+localityName_default            = Boston
+0.organizationName_default      = Red Hat
+organizationalUnitName_default  = Keycloak
+emailAddress_default            = contact@keycloak.org
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem
new file mode 100644
index 0000000..bcfaf61
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem
@@ -0,0 +1,69 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+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
+SCc=
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/intermediate.cert.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/intermediate.cert.pem
new file mode 100644
index 0000000..3521cbc
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/intermediate.cert.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/crlnumber b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/crlnumber
new file mode 100644
index 0000000..83b33d2
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/crlnumber
@@ -0,0 +1 @@
+1000
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/csr/intermediate.csr.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/csr/intermediate.csr.pem
new file mode 100644
index 0000000..0cc3a5b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/csr/intermediate.csr.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIE3jCCAsYCAQAwgZgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE
+BwwGQm9zdG9uMRAwDgYDVQQKDAdSZWQgSGF0MREwDwYDVQQLDAhLZXljbG9hazEh
+MB8GA1UEAwwYS2V5Y2xvYWsgSW50ZXJtZWRpYXRlIENBMSMwIQYJKoZIhvcNAQkB
+FhRjb250YWN0QGtleWNsb2FrLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
+AgoCggIBANiLHXMlNrpNOyY+Ny1zVHnq9g+wiER7JGKzscvyz4RsVsGk7yNZJJJo
+mnQxaRqFS1aJ271xYrnI8LR7NQPcthyWS0bVjrPF5joblGc0JSBXwRiR4IkCaUZW
+GAWNT7uvoc2HUvawsl6NQ4oywpwjG3VOmJRumH/cnVOuo9YMPWMjAH3fft29l9d3
+AhrjmmGTVJvvCBHpoHiYk8oGl6SSH/laHlBFcj7b5W/UyGrpK3HUx0Tg/a7yVuUg
+I6WcJohaIjoHbvKi3bGFyJ7XC8XBrWKq0Gvi0gcsifRc0rCqh6igz5YeWTCMwX9i
+nXNgkkmaReOHVrdkhPntZ7VTdHEmst/ETQPgab9LtDfTbHGIC4N3JwfHqjPiphjA
+hhlWT7/yrgINdXKjRoJjh71+wA+Ym/LlPApk4qhyiP4EUDJHA93WJWtIZ4BBMkE9
+wyC7vSj3FUGdTw+CyJ87kfOlfD0tNGsNpNLgFn+tgD08MvN7ExWuBUKD5fV1F3dP
+0iws86Wj4cKl80aF+BGXCnz9JEaYG6JobmTqRpJw/maKZIZg6+GNEcs2Rj5GC2X6
+GswOfwMV3vk+Jsz3mEaJr2TWpuuOaP2BEYDjHPVAGp7B3ZNOACForEMWpB5z5wnX
+m9/kDEHgD8qoWaphdhcBCkpzNu3aChPJvYCeeGlrlYl7+xi9ipNTAgMBAAGgADAN
+BgkqhkiG9w0BAQsFAAOCAgEAtZp+hULw+DW9TCzW1Sm1+r4cb6QN/DpWe4lvbSoU
+ah0oiUAa/xF9AaDR2woHvMWXzMehc42Z+4F40L+XSdM1VAg6B36BKM7fYiyGQExo
+bJF0oUqeRD6WneZNCd4APnmzAiMCU6uWzgLbkoUXw9JtNr3uxhIXvg3E+BasU5/F
+pb9UqTHBsSc1yAxhMT9zLOXLpkvX+mrWzkkbc09Schus8wM6naf6oWhgW5uNVQaw
+M3ZemlVmY7LYUwJKamNr7CRpzSPnFed+a77ogOFY1IjfuknYLPKlAaPtBuV5kEWB
+Bx0JjMNoGoqL+FxUqpX6+8RzksSGCecje6q3+j4nm8p2RrhVf4/dfupSTDI3ijGl
+Z0Y+eV0H88EySvnw6TKi9QCHBEc4TVKKA4wD6nASzMK2GtuqdutLJpd3ADgV/p32
+BZ/NM8aB2iGo5S4nnDwjvGIzaHgamZbLkAuFBTQtjzghgwJK0D5FtFmWxn+0PpP4
+IKntdvJXQVMuLL/CYa0L9BFcUbSNbglykfggGAv/kU0tOmDNdW6wv8IlN1c34KOM
+W2GYKDmcn5LTSzRmvN8E9kjvMLYVyFf8TeBpo8K34dkMRODu6LTQVu3EhKN2OZt9
+QXf79Y5zjNQwfdm2s4GBDK/+fkL04Hg69sbOeOID8aYQxy8fyxELad1fYsnas6P6
+u1I=
+-----END CERTIFICATE REQUEST-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt
new file mode 100644
index 0000000..60d4030
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt
@@ -0,0 +1 @@
+V	450708200730Z		1000	unknown	/C=US/ST=MA/L=Boston/O=Red Hat/OU=Keycloak/CN=test-user
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.attr b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.attr
new file mode 100644
index 0000000..8f7e63a
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.attr
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.old
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.old
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/newcerts/1000.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/newcerts/1000.pem
new file mode 100644
index 0000000..4a00a12
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/newcerts/1000.pem
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl.cnf b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl.cnf
new file mode 100644
index 0000000..acd341f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl.cnf
@@ -0,0 +1,135 @@
+# OpenSSL intermediate CA configuration file.
+
+[ ca ]
+# `man ca`
+default_ca = KeycloakICA
+
+[ KeycloakICA ]
+# Directory and file locations.
+dir               = ./intermediate
+certs             = $dir/certs
+crl_dir           = $dir/crl
+new_certs_dir     = $dir/newcerts
+database          = $dir/index.txt
+serial            = $dir/serial
+RANDFILE          = $dir/private/.rand
+
+# The root key and root certificate.
+private_key       = $dir/private/intermediate.key.pem
+certificate       = $dir/certs/intermediate.cert.pem
+
+# For certificate revocation lists.
+crlnumber         = $dir/crlnumber
+crl               = $dir/crl/intermediate.crl.pem
+crl_extensions    = crl_ext
+default_crl_days  = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md        = sha256
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_loose
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName             = match
+stateOrProvinceName     = match
+organizationName        = match
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits        = 2048
+distinguished_name  = req_distinguished_name
+string_mask         = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md          = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions     = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName                     = Country Name (2 letter code)
+stateOrProvinceName             = State or Province Name
+localityName                    = Locality Name
+0.organizationName              = Organization Name
+organizationalUnitName          = Organizational Unit Name
+commonName                      = Common Name
+emailAddress                    = Email Address
+
+# Optionally, specify some defaults.
+countryName_default             = US
+stateOrProvinceName_default     = MA
+localityName_default            = Boston
+0.organizationName_default      = Red Hat
+organizationalUnitName_default  = 
+emailAddress_default            = contact@keycloak.org
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+crlDistributionPoints = URI:http://localhost:8888/crl                                                    
+authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+crlDistributionPoints = URI:http://localhost:8888/crl
+authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl-san.cnf b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl-san.cnf
new file mode 100644
index 0000000..4bf6ffc
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl-san.cnf
@@ -0,0 +1,139 @@
+# OpenSSL intermediate CA configuration file.
+
+[ ca ]
+# `man ca`
+default_ca = KeycloakICA
+
+[ KeycloakICA ]
+# Directory and file locations.
+dir               = ./intermediate
+certs             = $dir/certs
+crl_dir           = $dir/crl
+new_certs_dir     = $dir/newcerts
+database          = $dir/index.txt
+serial            = $dir/serial
+RANDFILE          = $dir/private/.rand
+
+email_in_dn       = no
+
+# The root key and root certificate.
+private_key       = $dir/private/intermediate.key.pem
+certificate       = $dir/certs/intermediate.cert.pem
+
+# For certificate revocation lists.
+crlnumber         = $dir/crlnumber
+crl               = $dir/crl/intermediate.crl.pem
+crl_extensions    = crl_ext
+default_crl_days  = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md        = sha256
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_loose
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName             = match
+stateOrProvinceName     = match
+organizationName        = match
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits        = 2048
+distinguished_name  = req_distinguished_name
+string_mask         = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md          = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions     = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName                     = Country Name (2 letter code)
+stateOrProvinceName             = State or Province Name
+localityName                    = Locality Name
+0.organizationName              = Organization Name
+organizationalUnitName          = Organizational Unit Name
+commonName                      = Common Name
+emailAddress                    = Email Address
+
+# Optionally, specify some defaults.
+countryName_default             = US
+stateOrProvinceName_default     = MA
+localityName_default            = Boston
+0.organizationName_default      = Red Hat
+organizationalUnitName_default  = Keycloak
+emailAddress_default            = contact@keycloak.org
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+crlDistributionPoints = URI:http://localhost:8888/crl                                                    
+authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
+subjectAltName=email:copy
+subjectAltName=email:move
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+crlDistributionPoints = URI:http://localhost:8888/crl                                                    
+authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/private/intermediate.key.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/private/intermediate.key.pem
new file mode 100644
index 0000000..3116bf9
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/private/intermediate.key.pem
@@ -0,0 +1,54 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,55738491E62D25465F4122B4D81938FA
+
+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
+-----END RSA PRIVATE KEY-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial
new file mode 100644
index 0000000..dd11724
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial
@@ -0,0 +1 @@
+1001
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial.old
new file mode 100644
index 0000000..83b33d2
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial.old
@@ -0,0 +1 @@
+1000
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1000.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1000.pem
new file mode 100644
index 0000000..3521cbc
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1000.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/openssl.cnf b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/openssl.cnf
new file mode 100644
index 0000000..b596754
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/openssl.cnf
@@ -0,0 +1,131 @@
+# OpenSSL root CA configuration file.
+
+[ ca ]
+# `man ca`
+default_ca = Keycloak
+
+[ Keycloak ]
+# Directory and file locations.
+dir               = ./
+certs             = $dir/certs
+crl_dir           = $dir/crl
+new_certs_dir     = $dir/newcerts
+database          = $dir/index.txt
+serial            = $dir/serial
+RANDFILE          = $dir/private/.rand
+
+# The root key and root certificate.
+private_key       = $dir/private/ca.key.pem
+certificate       = $dir/certs/ca.cert.pem
+
+# For certificate revocation lists.
+crlnumber         = $dir/crlnumber
+crl               = $dir/crl/ca.crl.pem
+crl_extensions    = crl_ext
+default_crl_days  = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md        = sha256
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_strict
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName             = match
+stateOrProvinceName     = match
+organizationName        = match
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits        = 2048
+distinguished_name  = req_distinguished_name
+string_mask         = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md          = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions     = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName                     = Country Name (2 letter code)
+stateOrProvinceName             = State or Province Name
+localityName                    = Locality Name
+0.organizationName              = Organization Name
+organizationalUnitName          = Organizational Unit Name
+commonName                      = Common Name
+emailAddress                    = Email Address
+
+# Optionally, specify some defaults.
+countryName_default             = US
+stateOrProvinceName_default     = MA
+localityName_default            = Boston
+0.organizationName_default      = Red Hat
+organizationalUnitName_default  = Keycloak
+emailAddress_default            = contact@keycloak.org
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/private/ca.key.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/private/ca.key.pem
new file mode 100644
index 0000000..9a51de0
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/private/ca.key.pem
@@ -0,0 +1,54 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,0DB2418CD45582213A6DA1664904B74D
+
+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
+-----END RSA PRIVATE KEY-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial
new file mode 100644
index 0000000..dd11724
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial
@@ -0,0 +1 @@
+1001
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old
new file mode 100644
index 0000000..83b33d2
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old
@@ -0,0 +1 @@
+1000
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
index d66e09d..8160d26 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
@@ -245,6 +245,13 @@
                                                 <include>empty.crl</include>
                                             </includes>
                                         </resource>
+                                        <resource>
+                                            <directory>${common.resources}/pki/root/ca</directory>
+                                            <includes>
+                                                <include>certs/clients/test-user-san-email@localhost.cert.pem</include>
+                                                <include>certs/clients/test-user@localhost.key.pem</include>
+                                            </includes>
+                                        </resource>
                                     </resources>
                                 </configuration>
                             </execution>
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/keycloak.js b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/keycloak.js
new file mode 100644
index 0000000..80b4477
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/keycloak.js
@@ -0,0 +1,1416 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function( window, undefined ) {
+
+    var Keycloak = function (config) {
+        if (!(this instanceof Keycloak)) {
+            return new Keycloak(config);
+        }
+
+        var kc = this;
+        var adapter;
+        var refreshQueue = [];
+        var callbackStorage;
+
+        var loginIframe = {
+            enable: true,
+            callbackList: [],
+            interval: 5
+        };
+
+        var scripts = document.getElementsByTagName('script');
+        for (var i = 0; i < scripts.length; i++) {
+            if ((scripts[i].src.indexOf('keycloak.js') !== -1 || scripts[i].src.indexOf('keycloak.min.js') !== -1) && scripts[i].src.indexOf('version=') !== -1) {
+                kc.iframeVersion = scripts[i].src.substring(scripts[i].src.indexOf('version=') + 8).split('&')[0];
+            }
+        }
+
+        var useNonce = true;
+        
+        kc.init = function (initOptions) {
+            kc.authenticated = false;
+
+            callbackStorage = createCallbackStorage();
+
+            if (initOptions && initOptions.adapter === 'cordova') {
+                adapter = loadAdapter('cordova');
+            } else if (initOptions && initOptions.adapter === 'default') {
+                adapter = loadAdapter();
+            } else {
+                if (window.Cordova || window.cordova) {
+                    adapter = loadAdapter('cordova');
+                } else {
+                    adapter = loadAdapter();
+                }
+            }
+
+            if (initOptions) {
+                if (typeof initOptions.useNonce !== 'undefined') {
+                    useNonce = initOptions.useNonce;
+                }
+
+                if (typeof initOptions.checkLoginIframe !== 'undefined') {
+                    loginIframe.enable = initOptions.checkLoginIframe;
+                }
+
+                if (initOptions.checkLoginIframeInterval) {
+                    loginIframe.interval = initOptions.checkLoginIframeInterval;
+                }
+
+                if (initOptions.onLoad === 'login-required') {
+                    kc.loginRequired = true;
+                }
+
+                if (initOptions.responseMode) {
+                    if (initOptions.responseMode === 'query' || initOptions.responseMode === 'fragment') {
+                        kc.responseMode = initOptions.responseMode;
+                    } else {
+                        throw 'Invalid value for responseMode';
+                    }
+                }
+
+                if (initOptions.flow) {
+                    switch (initOptions.flow) {
+                        case 'standard':
+                            kc.responseType = 'code';
+                            break;
+                        case 'implicit':
+                            kc.responseType = 'id_token token';
+                            break;
+                        case 'hybrid':
+                            kc.responseType = 'code id_token token';
+                            break;
+                        default:
+                            throw 'Invalid value for flow';
+                    }
+                    kc.flow = initOptions.flow;
+                }
+
+                if (initOptions.timeSkew != null) {
+                    kc.timeSkew = initOptions.timeSkew;
+                }
+            }
+
+            if (!kc.responseMode) {
+                kc.responseMode = 'fragment';
+            }
+            if (!kc.responseType) {
+                kc.responseType = 'code';
+                kc.flow = 'standard';
+            }
+
+            var promise = createPromise();
+
+            var initPromise = createPromise();
+            initPromise.promise.success(function() {
+                kc.onReady && kc.onReady(kc.authenticated);
+                promise.setSuccess(kc.authenticated);
+            }).error(function(errorData) {
+                promise.setError(errorData);
+            });
+
+            var configPromise = loadConfig(config);
+
+            function onLoad() {
+                var doLogin = function(prompt) {
+                    if (!prompt) {
+                        options.prompt = 'none';
+                    }
+                    kc.login(options).success(function () {
+                        initPromise.setSuccess();
+                    }).error(function () {
+                        initPromise.setError();
+                    });
+                }
+
+                var options = {};
+                switch (initOptions.onLoad) {
+                    case 'check-sso':
+                        if (loginIframe.enable) {
+                            setupCheckLoginIframe().success(function() {
+                                checkLoginIframe().success(function () {
+                                    doLogin(false);
+                                }).error(function () {
+                                    initPromise.setSuccess();
+                                });
+                            });
+                        } else {
+                            doLogin(false);
+                        }
+                        break;
+                    case 'login-required':
+                        doLogin(true);
+                        break;
+                    default:
+                        throw 'Invalid value for onLoad';
+                }
+            }
+
+            function processInit() {
+                var callback = parseCallback(window.location.href);
+
+                if (callback) {
+                    window.history.replaceState({}, null, callback.newUrl);
+                }
+
+                if (callback && callback.valid) {
+                    return setupCheckLoginIframe().success(function() {
+                        processCallback(callback, initPromise);
+                    }).error(function (e) {
+                        initPromise.setError();
+                    });
+                } else if (initOptions) {
+                    if (initOptions.token && initOptions.refreshToken) {
+                        setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
+
+                        if (loginIframe.enable) {
+                            setupCheckLoginIframe().success(function() {
+                                checkLoginIframe().success(function () {
+                                    kc.onAuthSuccess && kc.onAuthSuccess();
+                                    initPromise.setSuccess();
+                                }).error(function () {
+                                    setToken(null, null, null);
+                                    initPromise.setSuccess();
+                                });
+                            });
+                        } else {
+                            kc.updateToken(-1).success(function() {
+                                kc.onAuthSuccess && kc.onAuthSuccess();
+                                initPromise.setSuccess();
+                            }).error(function() {
+                                kc.onAuthError && kc.onAuthError();
+                                if (initOptions.onLoad) {
+                                    onLoad();
+                                } else {
+                                    initPromise.setError();
+                                }
+                            });
+                        }
+                    } else if (initOptions.onLoad) {
+                        onLoad();
+                    } else {
+                        initPromise.setSuccess();
+                    }
+                } else {
+                    initPromise.setSuccess();
+                }
+            }
+
+            configPromise.success(processInit);
+            configPromise.error(function() {
+                promise.setError();
+            });
+
+            return promise.promise;
+        }
+
+        kc.login = function (options) {
+            return adapter.login(options);
+        }
+
+        kc.createLoginUrl = function(options) {
+            var state = createUUID();
+            var nonce = createUUID();
+
+            var redirectUri = adapter.redirectUri(options);
+
+            var callbackState = {
+                state: state,
+                nonce: nonce,
+                redirectUri: encodeURIComponent(redirectUri)
+            }
+
+            if (options && options.prompt) {
+                callbackState.prompt = options.prompt;
+            }
+
+            callbackStorage.add(callbackState);
+
+            var baseUrl;
+            if (options && options.action == 'register') {
+                baseUrl = kc.endpoints.register();
+            } else {
+                baseUrl = kc.endpoints.authorize();
+            }
+
+            var scope = (options && options.scope) ? "openid " + options.scope : "openid";
+
+            var url = baseUrl
+                + '?client_id=' + encodeURIComponent(kc.clientId)
+                + '&redirect_uri=' + encodeURIComponent(redirectUri)
+                + '&state=' + encodeURIComponent(state)
+                + '&response_mode=' + encodeURIComponent(kc.responseMode)
+                + '&response_type=' + encodeURIComponent(kc.responseType)
+                + '&scope=' + encodeURIComponent(scope);
+                if (useNonce) {
+                    url = url + '&nonce=' + encodeURIComponent(nonce);
+                }
+
+            if (options && options.prompt) {
+                url += '&prompt=' + encodeURIComponent(options.prompt);
+            }
+
+            if (options && options.maxAge) {
+                url += '&max_age=' + encodeURIComponent(options.maxAge);
+            }
+
+            if (options && options.loginHint) {
+                url += '&login_hint=' + encodeURIComponent(options.loginHint);
+            }
+
+            if (options && options.idpHint) {
+                url += '&kc_idp_hint=' + encodeURIComponent(options.idpHint);
+            }
+
+            if (options && options.locale) {
+                url += '&ui_locales=' + encodeURIComponent(options.locale);
+            }
+
+            return url;
+        }
+
+        kc.logout = function(options) {
+            return adapter.logout(options);
+        }
+
+        kc.createLogoutUrl = function(options) {
+            var url = kc.endpoints.logout()
+                + '?redirect_uri=' + encodeURIComponent(adapter.redirectUri(options, false));
+
+            return url;
+        }
+
+        kc.register = function (options) {
+            return adapter.register(options);
+        }
+
+        kc.createRegisterUrl = function(options) {
+            if (!options) {
+                options = {};
+            }
+            options.action = 'register';
+            return kc.createLoginUrl(options);
+        }
+
+        kc.createAccountUrl = function(options) {
+            var realm = getRealmUrl();
+            var url = undefined;
+            if (typeof realm !== 'undefined') {
+                url = realm
+                + '/account'
+                + '?referrer=' + encodeURIComponent(kc.clientId)
+                + '&referrer_uri=' + encodeURIComponent(adapter.redirectUri(options));
+            }
+            return url;
+        }
+
+        kc.accountManagement = function() {
+            return adapter.accountManagement();
+        }
+
+        kc.hasRealmRole = function (role) {
+            var access = kc.realmAccess;
+            return !!access && access.roles.indexOf(role) >= 0;
+        }
+
+        kc.hasResourceRole = function(role, resource) {
+            if (!kc.resourceAccess) {
+                return false;
+            }
+
+            var access = kc.resourceAccess[resource || kc.clientId];
+            return !!access && access.roles.indexOf(role) >= 0;
+        }
+
+        kc.loadUserProfile = function() {
+            var url = getRealmUrl() + '/account';
+            var req = new XMLHttpRequest();
+            req.open('GET', url, true);
+            req.setRequestHeader('Accept', 'application/json');
+            req.setRequestHeader('Authorization', 'bearer ' + kc.token);
+
+            var promise = createPromise();
+
+            req.onreadystatechange = function () {
+                if (req.readyState == 4) {
+                    if (req.status == 200) {
+                        kc.profile = JSON.parse(req.responseText);
+                        promise.setSuccess(kc.profile);
+                    } else {
+                        promise.setError();
+                    }
+                }
+            }
+
+            req.send();
+
+            return promise.promise;
+        }
+
+        kc.loadUserInfo = function() {
+            var url = kc.endpoints.userinfo();
+            var req = new XMLHttpRequest();
+            req.open('GET', url, true);
+            req.setRequestHeader('Accept', 'application/json');
+            req.setRequestHeader('Authorization', 'bearer ' + kc.token);
+
+            var promise = createPromise();
+
+            req.onreadystatechange = function () {
+                if (req.readyState == 4) {
+                    if (req.status == 200) {
+                        kc.userInfo = JSON.parse(req.responseText);
+                        promise.setSuccess(kc.userInfo);
+                    } else {
+                        promise.setError();
+                    }
+                }
+            }
+
+            req.send();
+
+            return promise.promise;
+        }
+
+        kc.isTokenExpired = function(minValidity) {
+            if (!kc.tokenParsed || (!kc.refreshToken && kc.flow != 'implicit' )) {
+                throw 'Not authenticated';
+            }
+
+            if (kc.timeSkew == null) {
+                console.info('[KEYCLOAK] Unable to determine if token is expired as timeskew is not set');
+                return true;
+            }
+
+            var expiresIn = kc.tokenParsed['exp'] - Math.ceil(new Date().getTime() / 1000) + kc.timeSkew;
+            if (minValidity) {
+                expiresIn -= minValidity;
+            }
+            return expiresIn < 0;
+        }
+
+        kc.updateToken = function(minValidity) {
+            var promise = createPromise();
+
+            if (!kc.refreshToken) {
+                promise.setError();
+                return promise.promise;
+            }
+
+            minValidity = minValidity || 5;
+
+            var exec = function() {
+                var refreshToken = false;
+                if (minValidity == -1) {
+                    refreshToken = true;
+                    console.info('[KEYCLOAK] Refreshing token: forced refresh');
+                } else if (!kc.tokenParsed || kc.isTokenExpired(minValidity)) {
+                    refreshToken = true;
+                    console.info('[KEYCLOAK] Refreshing token: token expired');
+                }
+
+                if (!refreshToken) {
+                    promise.setSuccess(false);
+                } else {
+                    var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
+                    var url = kc.endpoints.token();
+
+                    refreshQueue.push(promise);
+
+                    if (refreshQueue.length == 1) {
+                        var req = new XMLHttpRequest();
+                        req.open('POST', url, true);
+                        req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+                        req.withCredentials = true;
+
+                        if (kc.clientId && kc.clientSecret) {
+                            req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
+                        } else {
+                            params += '&client_id=' + encodeURIComponent(kc.clientId);
+                        }
+
+                        var timeLocal = new Date().getTime();
+
+                        req.onreadystatechange = function () {
+                            if (req.readyState == 4) {
+                                if (req.status == 200) {
+                                    console.info('[KEYCLOAK] Token refreshed');
+
+                                    timeLocal = (timeLocal + new Date().getTime()) / 2;
+
+                                    var tokenResponse = JSON.parse(req.responseText);
+
+                                    setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], timeLocal);
+
+                                    kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
+                                    for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
+                                        p.setSuccess(true);
+                                    }
+                                } else {
+                                    console.warn('[KEYCLOAK] Failed to refresh token');
+
+                                    kc.onAuthRefreshError && kc.onAuthRefreshError();
+                                    for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
+                                        p.setError(true);
+                                    }
+                                }
+                            }
+                        };
+
+                        req.send(params);
+                    }
+                }
+            }
+
+            if (loginIframe.enable) {
+                var iframePromise = checkLoginIframe();
+                iframePromise.success(function() {
+                    exec();
+                }).error(function() {
+                    promise.setError();
+                });
+            } else {
+                exec();
+            }
+
+            return promise.promise;
+        }
+
+        kc.clearToken = function() {
+            if (kc.token) {
+                setToken(null, null, null);
+                kc.onAuthLogout && kc.onAuthLogout();
+                if (kc.loginRequired) {
+                    kc.login();
+                }
+            }
+        }
+
+        function getRealmUrl() {
+            if (typeof kc.authServerUrl !== 'undefined') {
+                if (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
+                    return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
+                } else {
+                    return kc.authServerUrl + '/realms/' + encodeURIComponent(kc.realm);
+                }
+            } else {
+            	return undefined;
+            }
+        }
+
+        function getOrigin() {
+            if (!window.location.origin) {
+                return window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
+            } else {
+                return window.location.origin;
+            }
+        }
+
+        function processCallback(oauth, promise) {
+            var code = oauth.code;
+            var error = oauth.error;
+            var prompt = oauth.prompt;
+
+            var timeLocal = new Date().getTime();
+
+            if (error) {
+                if (prompt != 'none') {
+                    var errorData = { error: error, error_description: oauth.error_description };
+                    kc.onAuthError && kc.onAuthError(errorData);
+                    promise && promise.setError(errorData);
+                } else {
+                    promise && promise.setSuccess();
+                }
+                return;
+            } else if ((kc.flow != 'standard') && (oauth.access_token || oauth.id_token)) {
+                authSuccess(oauth.access_token, null, oauth.id_token, true);
+            }
+
+            if ((kc.flow != 'implicit') && code) {
+                var params = 'code=' + code + '&grant_type=authorization_code';
+                var url = kc.endpoints.token();
+
+                var req = new XMLHttpRequest();
+                req.open('POST', url, true);
+                req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+
+                if (kc.clientId && kc.clientSecret) {
+                    req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
+                } else {
+                    params += '&client_id=' + encodeURIComponent(kc.clientId);
+                }
+
+                params += '&redirect_uri=' + oauth.redirectUri;
+
+                req.withCredentials = true;
+
+                req.onreadystatechange = function() {
+                    if (req.readyState == 4) {
+                        if (req.status == 200) {
+
+                            var tokenResponse = JSON.parse(req.responseText);
+                            authSuccess(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], kc.flow === 'standard');
+                        } else {
+                            kc.onAuthError && kc.onAuthError();
+                            promise && promise.setError();
+                        }
+                    }
+                };
+
+                req.send(params);
+            }
+
+            function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
+                timeLocal = (timeLocal + new Date().getTime()) / 2;
+
+                setToken(accessToken, refreshToken, idToken, timeLocal);
+
+                if (useNonce && ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
+                    (kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
+                    (kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce))) {
+
+                    console.info('[KEYCLOAK] Invalid nonce, clearing token');
+                    kc.clearToken();
+                    promise && promise.setError();
+                } else {
+                    if (fulfillPromise) {
+                        kc.onAuthSuccess && kc.onAuthSuccess();
+                        promise && promise.setSuccess();
+                    }
+                }
+            }
+
+        }
+
+        function loadConfig(url) {
+            var promise = createPromise();
+            var configUrl;
+
+            if (!config) {
+                configUrl = 'keycloak.json';
+            } else if (typeof config === 'string') {
+                configUrl = config;
+            }
+
+            function setupOidcEndoints(oidcConfiguration) {
+                if (! oidcConfiguration) {
+                    kc.endpoints = {
+                        authorize: function() {
+                            return getRealmUrl() + '/protocol/openid-connect/auth';
+                        },
+                        token: function() {
+                            return getRealmUrl() + '/protocol/openid-connect/token';
+                        },
+                        logout: function() {
+                            return getRealmUrl() + '/protocol/openid-connect/logout';
+                        },
+                        checkSessionIframe: function() {
+                            var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
+                            if (kc.iframeVersion) {
+                              src = src + '?version=' + kc.iframeVersion;
+                            }
+                            return src;
+                        },
+                        register: function() {
+                            return getRealmUrl() + '/protocol/openid-connect/registrations';
+                        },
+                        userinfo: function() {
+                            return getRealmUrl() + '/protocol/openid-connect/userinfo';
+                        }
+                    };
+                } else {
+                    kc.endpoints = {
+                        authorize: function() {
+                            return oidcConfiguration.authorization_endpoint;
+                        },
+                        token: function() {
+                            return oidcConfiguration.token_endpoint;
+                        },
+                        logout: function() {
+                            if (!oidcConfiguration.end_session_endpoint) {
+                                throw "Not supported by the OIDC server";
+                            }
+                            return oidcConfiguration.end_session_endpoint;
+                        },
+                        checkSessionIframe: function() {
+                            if (!oidcConfiguration.check_session_iframe) {
+                                throw "Not supported by the OIDC server";
+                            }
+                            return oidcConfiguration.check_session_iframe;
+                        },
+                        register: function() {
+                            throw 'Redirection to "Register user" page not supported in standard OIDC mode';
+                        },
+                        userinfo: function() {
+                            if (!oidcConfiguration.userinfo_endpoint) {
+                                throw "Not supported by the OIDC server";
+                            }
+                            return oidcConfiguration.userinfo_endpoint;
+                        }
+                    }
+                }
+            }
+
+            if (configUrl) {
+                var req = new XMLHttpRequest();
+                req.open('GET', configUrl, true);
+                req.setRequestHeader('Accept', 'application/json');
+
+                req.onreadystatechange = function () {
+                    if (req.readyState == 4) {
+                        if (req.status == 200 || fileLoaded(req)) {
+                            var config = JSON.parse(req.responseText);
+
+                            kc.authServerUrl = config['auth-server-url'];
+                            kc.realm = config['realm'];
+                            kc.clientId = config['resource'];
+                            kc.clientSecret = (config['credentials'] || {})['secret'];
+                            setupOidcEndoints(null);
+                            promise.setSuccess();
+                        } else {
+                            promise.setError();
+                        }
+                    }
+                };
+
+                req.send();
+            } else {
+                if (!config.clientId) {
+                    throw 'clientId missing';
+                }
+
+                kc.clientId = config.clientId;
+                kc.clientSecret = (config.credentials || {}).secret;
+
+                var oidcProvider = config['oidcProvider'];
+                if (!oidcProvider) {
+                    if (!config['url']) {
+                        var scripts = document.getElementsByTagName('script');
+                        for (var i = 0; i < scripts.length; i++) {
+                            if (scripts[i].src.match(/.*keycloak\.js/)) {
+                                config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
+                                break;
+                            }
+                        }
+                    }
+                    if (!config.realm) {
+                        throw 'realm missing';
+                    }
+
+                    kc.authServerUrl = config.url;
+                    kc.realm = config.realm;
+                    setupOidcEndoints(null);
+                    promise.setSuccess();
+                } else {
+                    if (typeof oidcProvider === 'string') {
+                        var oidcProviderConfigUrl;
+                        if (oidcProvider.charAt(oidcProvider.length - 1) == '/') {
+                            oidcProviderConfigUrl = oidcProvider + '.well-known/openid-configuration';
+                        } else {
+                            oidcProviderConfigUrl = oidcProvider + '/.well-known/openid-configuration';
+                        }
+                        var req = new XMLHttpRequest();
+                        req.open('GET', oidcProviderConfigUrl, true);
+                        req.setRequestHeader('Accept', 'application/json');
+
+                        req.onreadystatechange = function () {
+                            if (req.readyState == 4) {
+                                if (req.status == 200 || fileLoaded(req)) {
+                                    var oidcProviderConfig = JSON.parse(req.responseText);
+                                    setupOidcEndoints(oidcProviderConfig);
+                                    promise.setSuccess();
+                                } else {
+                                    promise.setError();
+                                }
+                            }
+                        };
+
+                        req.send();
+                    } else {
+                        setupOidcEndoints(oidcProvider);
+                        promise.setSuccess();
+                    }
+                }
+            }
+
+            return promise.promise;
+        }
+
+        function fileLoaded(xhr) {
+            return xhr.status == 0 && xhr.responseText && xhr.responseURL.startsWith('file:');
+        }
+
+        function setToken(token, refreshToken, idToken, timeLocal) {
+            if (kc.tokenTimeoutHandle) {
+                clearTimeout(kc.tokenTimeoutHandle);
+                kc.tokenTimeoutHandle = null;
+            }
+
+            if (refreshToken) {
+                kc.refreshToken = refreshToken;
+                kc.refreshTokenParsed = decodeToken(refreshToken);
+            } else {
+                delete kc.refreshToken;
+                delete kc.refreshTokenParsed;
+            }
+
+            if (idToken) {
+                kc.idToken = idToken;
+                kc.idTokenParsed = decodeToken(idToken);
+            } else {
+                delete kc.idToken;
+                delete kc.idTokenParsed;
+            }
+
+            if (token) {
+                kc.token = token;
+                kc.tokenParsed = decodeToken(token);
+                kc.sessionId = kc.tokenParsed.session_state;
+                kc.authenticated = true;
+                kc.subject = kc.tokenParsed.sub;
+                kc.realmAccess = kc.tokenParsed.realm_access;
+                kc.resourceAccess = kc.tokenParsed.resource_access;
+
+                if (timeLocal) {
+                    kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
+                }
+
+                if (kc.timeSkew != null) {
+                    console.info('[KEYCLOAK] Estimated time difference between browser and server is ' + kc.timeSkew + ' seconds');
+
+                    if (kc.onTokenExpired) {
+                        var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
+                        console.info('[KEYCLOAK] Token expires in ' + Math.round(expiresIn / 1000) + ' s');
+                        if (expiresIn <= 0) {
+                            kc.onTokenExpired();
+                        } else {
+                            kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
+                        }
+                    }
+                }
+            } else {
+                delete kc.token;
+                delete kc.tokenParsed;
+                delete kc.subject;
+                delete kc.realmAccess;
+                delete kc.resourceAccess;
+
+                kc.authenticated = false;
+            }
+        }
+
+        function decodeToken(str) {
+            str = str.split('.')[1];
+
+            str = str.replace('/-/g', '+');
+            str = str.replace('/_/g', '/');
+            switch (str.length % 4)
+            {
+                case 0:
+                    break;
+                case 2:
+                    str += '==';
+                    break;
+                case 3:
+                    str += '=';
+                    break;
+                default:
+                    throw 'Invalid token';
+            }
+
+            str = (str + '===').slice(0, str.length + (str.length % 4));
+            str = str.replace(/-/g, '+').replace(/_/g, '/');
+
+            str = decodeURIComponent(escape(atob(str)));
+
+            str = JSON.parse(str);
+            return str;
+        }
+
+        function createUUID() {
+            var s = [];
+            var hexDigits = '0123456789abcdef';
+            for (var i = 0; i < 36; i++) {
+                s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+            }
+            s[14] = '4';
+            s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
+            s[8] = s[13] = s[18] = s[23] = '-';
+            var uuid = s.join('');
+            return uuid;
+        }
+
+        kc.callback_id = 0;
+
+        function createCallbackId() {
+            var id = '<id: ' + (kc.callback_id++) + (Math.random()) + '>';
+            return id;
+
+        }
+
+        function parseCallback(url) {
+            var oauth = parseCallbackUrl(url);
+            if (!oauth) {
+                return;
+            }
+
+            var oauthState = callbackStorage.get(oauth.state);
+
+            if (oauthState) {
+                oauth.valid = true;
+                oauth.redirectUri = oauthState.redirectUri;
+                oauth.storedNonce = oauthState.nonce;
+                oauth.prompt = oauthState.prompt;
+            }
+
+            return oauth;
+        }
+
+        function parseCallbackUrl(url) {
+            var supportedParams;
+            switch (kc.flow) {
+                case 'standard':
+                    supportedParams = ['code', 'state', 'session_state'];
+                    break;
+                case 'implicit':
+                    supportedParams = ['access_token', 'id_token', 'state', 'session_state'];
+                    break;
+                case 'hybrid':
+                    supportedParams = ['access_token', 'id_token', 'code', 'state', 'session_state'];
+                    break;
+            }
+
+            supportedParams.push('error');
+            supportedParams.push('error_description');
+            supportedParams.push('error_uri');
+
+            var queryIndex = url.indexOf('?');
+            var fragmentIndex = url.indexOf('#');
+
+            var newUrl;
+            var parsed;
+
+            if (kc.responseMode === 'query' && queryIndex !== -1) {
+                newUrl = url.substring(0, queryIndex);
+                parsed = parseCallbackParams(url.substring(queryIndex + 1, fragmentIndex !== -1 ? fragmentIndex : url.length), supportedParams);
+                if (parsed.paramsString !== '') {
+                    newUrl += '?' + parsed.paramsString;
+                }
+                if (fragmentIndex !== -1) {
+                    newUrl += url.substring(fragmentIndex);
+                }
+            } else if (kc.responseMode === 'fragment' && fragmentIndex !== -1) {
+                newUrl = url.substring(0, fragmentIndex);
+                parsed = parseCallbackParams(url.substring(fragmentIndex + 1), supportedParams);
+                if (parsed.paramsString !== '') {
+                    newUrl += '#' + parsed.paramsString;
+                }
+            }
+
+            if (parsed && parsed.oauthParams) {
+                if (kc.flow === 'standard' || kc.flow === 'hybrid') {
+                    if ((parsed.oauthParams.code || parsed.oauthParams.error) && parsed.oauthParams.state) {
+                        parsed.oauthParams.newUrl = newUrl;
+                        return parsed.oauthParams;
+                    }
+                } else if (kc.flow === 'implicit') {
+                    if ((parsed.oauthParams.access_token || parsed.oauthParams.error) && parsed.oauthParams.state) {
+                        parsed.oauthParams.newUrl = newUrl;
+                        return parsed.oauthParams;
+                    }
+                }
+            }
+        }
+
+        function parseCallbackParams(paramsString, supportedParams) {
+            var p = paramsString.split('&');
+            var result = {
+                paramsString: '',
+                oauthParams: {}
+            }
+            for (var i = 0; i < p.length; i++) {
+                var t = p[i].split('=');
+                if (supportedParams.indexOf(t[0]) !== -1) {
+                    result.oauthParams[t[0]] = t[1];
+                } else {
+                    if (result.paramsString !== '') {
+                        result.paramsString += '&';
+                    }
+                    result.paramsString += p[i];
+                }
+            }
+            return result;
+        }
+
+        function createPromise() {
+            if (typeof Promise === "function") {
+                return createNativePromise();
+            } else {
+                return createLegacyPromise();
+            }
+        }
+
+        function createNativePromise() {
+            // Need to create a native Promise which also preserves the
+            // interface of the custom promise type previously used by the API
+            var p = {
+                setSuccess: function(result) {
+                    p.success = true;
+                    p.resolve(result);
+                },
+
+                setError: function(result) {
+                    p.success = false;
+                    p.reject(result);
+                }
+            };
+            p.promise = new Promise(function(resolve, reject) {
+                p.resolve = resolve;
+                p.reject = reject;
+            });
+            p.promise.success = function(callback) {
+                p.promise.then(callback);
+                return p.promise;
+            }
+            p.promise.error = function(callback) {
+                p.promise.catch(callback);
+                return p.promise;
+            }
+            return p;
+        }
+
+        function createLegacyPromise() {
+            var p = {
+                setSuccess: function(result) {
+                    p.success = true;
+                    p.result = result;
+                    if (p.successCallback) {
+                        p.successCallback(result);
+                    }
+                },
+
+                setError: function(result) {
+                    p.error = true;
+                    p.result = result;
+                    if (p.errorCallback) {
+                        p.errorCallback(result);
+                    }
+                },
+
+                promise: {
+                    success: function(callback) {
+                        if (p.success) {
+                            callback(p.result);
+                        } else if (!p.error) {
+                            p.successCallback = callback;
+                        }
+                        return p.promise;
+                    },
+                    error: function(callback) {
+                        if (p.error) {
+                            callback(p.result);
+                        } else if (!p.success) {
+                            p.errorCallback = callback;
+                        }
+                        return p.promise;
+                    }
+                }
+            }
+            return p;
+        }
+
+        function setupCheckLoginIframe() {
+            var promise = createPromise();
+
+            if (!loginIframe.enable) {
+                promise.setSuccess();
+                return promise.promise;
+            }
+
+            if (loginIframe.iframe) {
+                promise.setSuccess();
+                return promise.promise;
+            }
+
+            var iframe = document.createElement('iframe');
+            loginIframe.iframe = iframe;
+
+            iframe.onload = function() {
+                var authUrl = kc.endpoints.authorize();
+                if (authUrl.charAt(0) === '/') {
+                    loginIframe.iframeOrigin = getOrigin();
+                } else {
+                    loginIframe.iframeOrigin = authUrl.substring(0, authUrl.indexOf('/', 8));
+                }
+                promise.setSuccess();
+
+                setTimeout(check, loginIframe.interval * 1000);
+            }
+
+            var src = kc.endpoints.checkSessionIframe();
+            iframe.setAttribute('src', src );
+            iframe.setAttribute('title', 'keycloak-session-iframe' );
+            iframe.style.display = 'none';
+            document.body.appendChild(iframe);
+
+            var messageCallback = function(event) {
+                if ((event.origin !== loginIframe.iframeOrigin) || (loginIframe.iframe.contentWindow !== event.source)) {
+                    return;
+                }
+
+                if (!(event.data == 'unchanged' || event.data == 'changed' || event.data == 'error')) {
+                    return;
+                }
+
+
+                if (event.data != 'unchanged') {
+                    kc.clearToken();
+                }
+
+                var callbacks = loginIframe.callbackList.splice(0, loginIframe.callbackList.length);
+
+                for (var i = callbacks.length - 1; i >= 0; --i) {
+                    var promise = callbacks[i];
+                    if (event.data == 'unchanged') {
+                        promise.setSuccess();
+                    } else {
+                        promise.setError();
+                    }
+                }
+            };
+
+            window.addEventListener('message', messageCallback, false);
+
+            var check = function() {
+                checkLoginIframe();
+                if (kc.token) {
+                    setTimeout(check, loginIframe.interval * 1000);
+                }
+            };
+
+            return promise.promise;
+        }
+
+        function checkLoginIframe() {
+            var promise = createPromise();
+
+            if (loginIframe.iframe && loginIframe.iframeOrigin ) {
+                var msg = kc.clientId + ' ' + kc.sessionId;
+                loginIframe.callbackList.push(promise);
+                var origin = loginIframe.iframeOrigin;
+                if (loginIframe.callbackList.length == 1) {
+                    loginIframe.iframe.contentWindow.postMessage(msg, origin);
+                }
+            } else {
+                promise.setSuccess();
+            }
+
+            return promise.promise;
+        }
+
+        function loadAdapter(type) {
+            if (!type || type == 'default') {
+                return {
+                    login: function(options) {
+                        window.location.href = kc.createLoginUrl(options);
+                        return createPromise().promise;
+                    },
+
+                    logout: function(options) {
+                        window.location.href = kc.createLogoutUrl(options);
+                        return createPromise().promise;
+                    },
+
+                    register: function(options) {
+                        window.location.href = kc.createRegisterUrl(options);
+                        return createPromise().promise;
+                    },
+
+                    accountManagement : function() {
+                        var accountUrl = kc.createAccountUrl();
+                        if (typeof accountUrl !== 'undefined') {
+                            window.location.href = accountUrl;
+                        } else {
+                            throw "Not supported by the OIDC server";
+                        }
+                        return createPromise().promise;
+                    },
+
+                    redirectUri: function(options, encodeHash) {
+                        if (arguments.length == 1) {
+                            encodeHash = true;
+                        }
+
+                        if (options && options.redirectUri) {
+                            return options.redirectUri;
+                        } else if (kc.redirectUri) {
+                            return kc.redirectUri;
+                        } else {
+                            return location.href;
+                        }
+                    }
+                };
+            }
+
+            if (type == 'cordova') {
+                loginIframe.enable = false;
+                var cordovaOpenWindowWrapper = function(loginUrl, target, options) {
+                    if (window.cordova && window.cordova.InAppBrowser) {
+                        // Use inappbrowser for IOS and Android if available
+                        return window.cordova.InAppBrowser.open(loginUrl, target, options);
+                    } else {
+                        return window.open(loginUrl, target, options);
+                    }
+                };
+                return {
+                    login: function(options) {
+                        var promise = createPromise();
+
+                        var o = 'location=no';
+                        if (options && options.prompt == 'none') {
+                            o += ',hidden=yes';
+                        }
+
+                        var loginUrl = kc.createLoginUrl(options);
+                        var ref = cordovaOpenWindowWrapper(loginUrl, '_blank', o);
+                        var completed = false;
+
+                        ref.addEventListener('loadstart', function(event) {
+                            if (event.url.indexOf('http://localhost') == 0) {
+                                var callback = parseCallback(event.url);
+                                processCallback(callback, promise);
+                                ref.close();
+                                completed = true;
+                            }
+                        });
+
+                        ref.addEventListener('loaderror', function(event) {
+                            if (!completed) {
+                                if (event.url.indexOf('http://localhost') == 0) {
+                                    var callback = parseCallback(event.url);
+                                    processCallback(callback, promise);
+                                    ref.close();
+                                    completed = true;
+                                } else {
+                                    promise.setError();
+                                    ref.close();
+                                }
+                            }
+                        });
+
+                        return promise.promise;
+                    },
+
+                    logout: function(options) {
+                        var promise = createPromise();
+
+                        var logoutUrl = kc.createLogoutUrl(options);
+                        var ref = cordovaOpenWindowWrapper(logoutUrl, '_blank', 'location=no,hidden=yes');
+
+                        var error;
+
+                        ref.addEventListener('loadstart', function(event) {
+                            if (event.url.indexOf('http://localhost') == 0) {
+                                ref.close();
+                            }
+                        });
+
+                        ref.addEventListener('loaderror', function(event) {
+                            if (event.url.indexOf('http://localhost') == 0) {
+                                ref.close();
+                            } else {
+                                error = true;
+                                ref.close();
+                            }
+                        });
+
+                        ref.addEventListener('exit', function(event) {
+                            if (error) {
+                                promise.setError();
+                            } else {
+                                kc.clearToken();
+                                promise.setSuccess();
+                            }
+                        });
+
+                        return promise.promise;
+                    },
+
+                    register : function() {
+                        var registerUrl = kc.createRegisterUrl();
+                        var ref = cordovaOpenWindowWrapper(registerUrl, '_blank', 'location=no');
+                        ref.addEventListener('loadstart', function(event) {
+                            if (event.url.indexOf('http://localhost') == 0) {
+                                ref.close();
+                            }
+                        });
+                    },
+
+                    accountManagement : function() {
+                        var accountUrl = kc.createAccountUrl();
+                        if (typeof accountUrl !== 'undefined') {
+                            var ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no');
+                            ref.addEventListener('loadstart', function(event) {
+                                if (event.url.indexOf('http://localhost') == 0) {
+                                    ref.close();
+                                }
+                            });
+                        } else {
+                            throw "Not supported by the OIDC server";
+                        }
+                    },
+
+                    redirectUri: function(options) {
+                        return 'http://localhost';
+                    }
+                }
+            }
+
+            throw 'invalid adapter type: ' + type;
+        }
+
+        var LocalStorage = function() {
+            if (!(this instanceof LocalStorage)) {
+                return new LocalStorage();
+            }
+
+            localStorage.setItem('kc-test', 'test');
+            localStorage.removeItem('kc-test');
+
+            var cs = this;
+
+            function clearExpired() {
+                var time = new Date().getTime();
+                for (var i = 0; i < localStorage.length; i++)  {
+                    var key = localStorage.key(i);
+                    if (key && key.indexOf('kc-callback-') == 0) {
+                        var value = localStorage.getItem(key);
+                        if (value) {
+                            try {
+                                var expires = JSON.parse(value).expires;
+                                if (!expires || expires < time) {
+                                    localStorage.removeItem(key);
+                                }
+                            } catch (err) {
+                                localStorage.removeItem(key);
+                            }
+                        }
+                    }
+                }
+            }
+
+            cs.get = function(state) {
+                if (!state) {
+                    return;
+                }
+
+                var key = 'kc-callback-' + state;
+                var value = localStorage.getItem(key);
+                if (value) {
+                    localStorage.removeItem(key);
+                    value = JSON.parse(value);
+                }
+
+                clearExpired();
+                return value;
+            };
+
+            cs.add = function(state) {
+                clearExpired();
+
+                var key = 'kc-callback-' + state.state;
+                state.expires = new Date().getTime() + (60 * 60 * 1000);
+                localStorage.setItem(key, JSON.stringify(state));
+            };
+        };
+
+        var CookieStorage = function() {
+            if (!(this instanceof CookieStorage)) {
+                return new CookieStorage();
+            }
+
+            var cs = this;
+
+            cs.get = function(state) {
+                if (!state) {
+                    return;
+                }
+
+                var value = getCookie('kc-callback-' + state);
+                setCookie('kc-callback-' + state, '', cookieExpiration(-100));
+                if (value) {
+                    return JSON.parse(value);
+                }
+            };
+
+            cs.add = function(state) {
+                setCookie('kc-callback-' + state.state, JSON.stringify(state), cookieExpiration(60));
+            };
+
+            cs.removeItem = function(key) {
+                setCookie(key, '', cookieExpiration(-100));
+            };
+
+            var cookieExpiration = function (minutes) {
+                var exp = new Date();
+                exp.setTime(exp.getTime() + (minutes*60*1000));
+                return exp;
+            };
+
+            var getCookie = function (key) {
+                var name = key + '=';
+                var ca = document.cookie.split(';');
+                for (var i = 0; i < ca.length; i++) {
+                    var c = ca[i];
+                    while (c.charAt(0) == ' ') {
+                        c = c.substring(1);
+                    }
+                    if (c.indexOf(name) == 0) {
+                        return c.substring(name.length, c.length);
+                    }
+                }
+                return '';
+            };
+
+            var setCookie = function (key, value, expirationDate) {
+                var cookie = key + '=' + value + '; '
+                    + 'expires=' + expirationDate.toUTCString() + '; ';
+                document.cookie = cookie;
+            }
+        };
+
+        function createCallbackStorage() {
+            try {
+                return new LocalStorage();
+            } catch (err) {
+            }
+
+            return new CookieStorage();
+        }
+    }
+
+    if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+        module.exports = Keycloak;
+    } else {
+        window.Keycloak = Keycloak;
+
+        if ( typeof define === "function" && define.amd ) {
+            define( "keycloak", [], function () { return Keycloak; } );
+        }
+    }
+})( window );
diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/common/cache-authorization.xsl b/testsuite/integration-arquillian/servers/cache-server/jboss/common/cache-authorization.xsl
new file mode 100644
index 0000000..26ce283
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/cache-server/jboss/common/cache-authorization.xsl
@@ -0,0 +1,90 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<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 #all">
+
+    <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="nsCacheServer" select="'urn:infinispan:server:core:'"/>
+    <xsl:variable name="nsDomain" select="'urn:jboss:domain:'"/>
+    <xsl:variable name="nsEndpoint" select="'urn:infinispan:server:endpoint:'"/>
+
+    <!-- Configuration of infinispan caches in infinispan-subsystem -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsCacheServer)]
+                        /*[local-name()='cache-container' and starts-with(namespace-uri(), $nsCacheServer) and @name='clustered']">
+        <xsl:copy>
+            <xsl:apply-templates select="@*" />
+
+            <security>
+                <authorization>
+                    <identity-role-mapper/>
+                    <role name="___script_manager" permissions="ALL"/>
+                </authorization>
+            </security>
+
+            <xsl:apply-templates select="node()" />
+
+        </xsl:copy>
+    </xsl:template>
+
+    <!-- Add "authentication" into HotRod connector configuration -->
+    <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsEndpoint)]
+                        /*[local-name()='hotrod-connector' and starts-with(namespace-uri(), $nsEndpoint) and @cache-container='clustered']">
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()" />
+
+            <authentication security-realm="AllowScriptManager">
+                <sasl mechanisms="DIGEST-MD5" qop="auth" server-name="keycloak-jdg-server">
+                    <policy>
+                        <no-anonymous value="false" />
+                    </policy>
+                </sasl>
+            </authentication>
+        </xsl:copy>
+    </xsl:template>
+
+    <!-- Add "AllowScriptManager" security-realm -->
+    <xsl:template match="//*[local-name()='management' and starts-with(namespace-uri(), $nsDomain)]
+                        /*[local-name()='security-realms' and starts-with(namespace-uri(), $nsDomain)]">
+        <xsl:copy>
+            <xsl:apply-templates select="@* | node()" />
+
+            <xsl:element name="security-realm" namespace="{namespace-uri()}">
+                <xsl:attribute name="name">AllowScriptManager</xsl:attribute>
+                <xsl:element name="authentication" namespace="{namespace-uri()}">
+                    <xsl:element name="users" namespace="{namespace-uri()}">
+                        <xsl:element name="user" namespace="{namespace-uri()}">
+                            <xsl:attribute name="username">___script_manager</xsl:attribute>
+                            <xsl:element name="password" namespace="{namespace-uri()}">not-so-secret-password</xsl:element>
+                        </xsl:element>
+                    </xsl:element>
+                </xsl:element>
+            </xsl:element>
+        </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/cache-server/jboss/infinispan/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml
index a060fdd..82dbb2d 100644
--- a/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml
+++ b/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml
@@ -34,10 +34,11 @@
         <cache.server.container>cache-server-${cache.server}</cache.server.container>
         <cache.server.home>${containers.home}/${cache.server.container}</cache.server.home>
         
+        <cache.server.jboss.cache-authorization-disabled>true</cache.server.jboss.cache-authorization-disabled>
         <cache.server.jboss.groupId>org.infinispan.server</cache.server.jboss.groupId>
         <cache.server.jboss.artifactId>infinispan-server</cache.server.jboss.artifactId>
         <cache.server.jboss.version>${infinispan.version}</cache.server.jboss.version>
-        <cache.server.jboss.unpacked.folder.name>${cache.server.jboss.artifactId}-${infinispan.version}</cache.server.jboss.unpacked.folder.name>
+        <cache.server.jboss.unpacked.folder.name>${cache.server.jboss.artifactId}-${cache.server.jboss.version}</cache.server.jboss.unpacked.folder.name>
         
         <cache.server.worker.io-threads>${cache.default.worker.io-threads}</cache.server.worker.io-threads>
         <cache.server.worker.task-max-threads>${cache.default.worker.task-max-threads}</cache.server.worker.task-max-threads>
diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml
index f9780b7..16cfcbf 100644
--- a/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml
+++ b/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml
@@ -34,6 +34,7 @@
         <cache.server.container>cache-server-${cache.server}</cache.server.container>
         <cache.server.home>${containers.home}/${cache.server.container}</cache.server.home>
         
+        <cache.server.jboss.cache-authorization-disabled>false</cache.server.jboss.cache-authorization-disabled>
         <cache.server.jboss.groupId>org.infinispan.server</cache.server.jboss.groupId>
         <cache.server.jboss.artifactId>infinispan-server</cache.server.jboss.artifactId>
         <cache.server.jboss.version>${jdg.version}</cache.server.jboss.version>
diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml
index 96c80d1..2e9e1fc 100644
--- a/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml
+++ b/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml
@@ -33,6 +33,7 @@
         <common.resources>${project.parent.basedir}/common</common.resources>
         <assembly.xml>${project.parent.basedir}/assembly.xml</assembly.xml>
         <cache.server.jboss.home>${containers.home}/${cache.server.jboss.unpacked.folder.name}</cache.server.jboss.home>
+        <cache.server.jboss.cache-authorization-disabled>true</cache.server.jboss.cache-authorization-disabled>
         <security.xslt>security.xsl</security.xslt>
     </properties>
 
@@ -59,6 +60,7 @@
                                     <rules>
                                         <requireProperty>
                                             <property>cache.server</property>
+                                            <property>cache.server.jboss.cache-authorization-enabled</property>
                                             <property>cache.server.jboss.groupId</property>
                                             <property>cache.server.jboss.artifactId</property>
                                             <property>cache.server.jboss.version</property>
@@ -165,6 +167,29 @@
                             </execution>
 
                             <execution>
+                                <id>configure-keycloak-authorization</id>
+                                <phase>process-test-resources</phase>
+                                <goals>
+                                    <goal>transform</goal>
+                                </goals>
+                                <configuration>
+                                    <skip>${cache.server.jboss.cache-authorization-disabled}</skip>
+                                    <transformationSets>
+                                        <!-- Configure authorization in files clustered-__dc__.xml -->
+                                        <transformationSet>
+                                            <dir>${cache.server.jboss.home}/standalone/configuration</dir>
+                                            <includes>
+                                                <include>clustered-1.xml</include>
+                                                <include>clustered-2.xml</include>
+                                            </includes>
+                                            <stylesheet>${common.resources}/cache-authorization.xsl</stylesheet>
+                                            <outputDir>${cache.server.jboss.home}/standalone/configuration</outputDir>
+                                        </transformationSet>
+                                    </transformationSets>
+                                </configuration>
+                            </execution>
+
+                            <execution>
                                 <id>io-worker-threads</id>
                                 <phase>process-resources</phase>
                                 <goals>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html
index 692e05d..a66fcdc 100755
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html
@@ -31,6 +31,7 @@
     <div id="content" ng-view/>
 </div>
 
+<div style="display: none;" id="bearer"></div>
 <pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="output"></pre>
 
 </body>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js
index 3d2ed43..f6df2cb 100755
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js
@@ -166,8 +166,10 @@ module.factory('authInterceptor', function ($q, $injector, $timeout, Identity) {
             if (Identity.authorization && Identity.authorization.rpt && request.url.indexOf('/authorize') == -1) {
                 retries = 0;
                 request.headers.Authorization = 'Bearer ' + Identity.authorization.rpt;
+                document.getElementById("bearer").innerHTML = 'rpt: Bearer ' + Identity.authorization.rpt;
             } else {
                 request.headers.Authorization = 'Bearer ' + Identity.authc.token;
+                document.getElementById("bearer").innerHTML = 'authc: Bearer ' + Identity.authc.token;
             }
             return request;
         },
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
index 9070416..94feb72 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
@@ -3,19 +3,14 @@ package org.keycloak.example.photoz.album;
 import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.authorization.client.AuthzClient;
 import org.keycloak.authorization.client.ClientAuthorizationContext;
-import org.keycloak.authorization.client.Configuration;
 import org.keycloak.authorization.client.representation.ResourceRepresentation;
 import org.keycloak.authorization.client.representation.ScopeRepresentation;
 import org.keycloak.authorization.client.resource.ProtectionResource;
-import org.keycloak.example.photoz.ErrorResponse;
 import org.keycloak.example.photoz.entity.Album;
 import org.keycloak.example.photoz.util.Transaction;
-import org.keycloak.representations.adapters.config.AdapterConfig;
-import org.keycloak.util.JsonSerialization;
 
 import javax.inject.Inject;
 import javax.persistence.EntityManager;
-import javax.persistence.Query;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -28,16 +23,16 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
-import java.security.Principal;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
+import javax.ws.rs.core.HttpHeaders;
+import org.jboss.logging.Logger;
 
 @Path("/album")
 @Transaction
 public class AlbumService {
 
-    private static volatile long nextId = 0;
+    private final Logger log = Logger.getLogger(AlbumService.class);
 
     public static final String SCOPE_ALBUM_VIEW = "album:view";
     public static final String SCOPE_ALBUM_DELETE = "album:delete";
@@ -50,33 +45,35 @@ public class AlbumService {
 
     @POST
     @Consumes("application/json")
-    public Response create(Album newAlbum, @QueryParam("user") String username) {
-        newAlbum.setId(++nextId);
-
-        if (username == null) {
-            username = request.getUserPrincipal().getName();
+    public Response create(Album newAlbum, @QueryParam("user") String invalidUser, @Context HttpHeaders headers) {
+        printAuthHeaders(headers);
+        
+        String userId = request.getUserPrincipal().getName();
+        
+        if (invalidUser != null) {
+            userId = invalidUser;
         }
+        
+        newAlbum.setUserId(userId);
 
-        newAlbum.setUserId(username);
-        Query queryDuplicatedAlbum = this.entityManager.createQuery("from Album where name = :name and userId = :userId");
-
-        queryDuplicatedAlbum.setParameter("name", newAlbum.getName());
-        queryDuplicatedAlbum.setParameter("userId", username);
-
-        if (!queryDuplicatedAlbum.getResultList().isEmpty()) {
-            throw new ErrorResponse("Name [" + newAlbum.getName() + "] already taken. Choose another one.", Status.CONFLICT);
+        log.debug("PERSISTING " + newAlbum);
+        entityManager.persist(newAlbum);
+        try {
+            createProtectedResource(newAlbum);
+        } catch (RuntimeException e) {
+            log.debug("ERROR " + e);
+            entityManager.remove(newAlbum);
+            throw e;
         }
 
-        this.entityManager.persist(newAlbum);
-
-        createProtectedResource(newAlbum);
-
         return Response.ok(newAlbum).build();
     }
 
     @Path("{id}")
     @DELETE
-    public Response delete(@PathParam("id") String id) {
+    public Response delete(@PathParam("id") String id, @Context HttpHeaders headers) {
+        printAuthHeaders(headers);
+        
         Album album = this.entityManager.find(Album.class, Long.valueOf(id));
 
         try {
@@ -113,6 +110,7 @@ public class AlbumService {
     }
 
     private void createProtectedResource(Album album) {
+        log.debug("Creating ProtectedResource for " + album);
         try {
             HashSet<ScopeRepresentation> scopes = new HashSet<>();
 
@@ -145,7 +143,7 @@ public class AlbumService {
             }
 
             protection.resource().delete(search.get(0).getId());
-        } catch (Exception e) {
+        } catch (RuntimeException e) {
             throw new RuntimeException("Could not search protected resource.", e);
         }
     }
@@ -161,4 +159,11 @@ public class AlbumService {
     private KeycloakSecurityContext getKeycloakSecurityContext() {
         return KeycloakSecurityContext.class.cast(request.getAttribute(KeycloakSecurityContext.class.getName()));
     }
+
+    private void printAuthHeaders(HttpHeaders headers) {
+        log.debug("-----------------Authorization headers--------------------------");
+        for (String authHeader : headers.getRequestHeader(HttpHeaders.AUTHORIZATION)) {
+            log.debug(authHeader);
+        }
+    }
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
index f887e2a..6eadcbf 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
@@ -17,24 +17,30 @@
  */
 package org.keycloak.example.photoz.entity;
 
+import java.io.Serializable;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.Id;
 import javax.persistence.OneToMany;
-import javax.persistence.GenerationType;
 import javax.persistence.Transient;
 import java.util.ArrayList;
 import java.util.List;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
 @Entity
-public class Album {
+@Table(uniqueConstraints = {
+    @UniqueConstraint(columnNames = {"name", "userId"})
+})
+public class Album implements Serializable {
 
     @Id
+    @GeneratedValue
     private Long id;
 
     @Column(nullable = false)
@@ -88,4 +94,9 @@ public class Album {
     public void setUserManaged(boolean userManaged) {
         this.userManaged = userManaged;
     }
+
+    @Override
+    public String toString() {
+        return "Album{" + "id=" + id + ", name=" + name + ", userId=" + userId + '}';
+    }
 }
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
index 08b7495..1161807 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
@@ -17,6 +17,7 @@
  */
 package org.keycloak.example.photoz.entity;
 
+import java.io.Serializable;
 import javax.persistence.Basic;
 import javax.persistence.Column;
 import javax.persistence.Entity;
@@ -30,7 +31,7 @@ import javax.persistence.ManyToOne;
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
 @Entity
-public class Photo {
+public class Photo implements Serializable {
 
     @Id
     @GeneratedValue
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
index 36d35f3..be60248 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
@@ -35,7 +35,7 @@ public class TransactionInterceptor {
     private Instance<EntityManager> entityManager;
 
     @AroundInvoke
-    public Object aroundInvoke(InvocationContext context) {
+    public Object aroundInvoke(InvocationContext context) throws Exception {
         EntityManager entityManager = this.entityManager.get();
         EntityTransaction transaction = entityManager.getTransaction();
 
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
index 8b6d226..369d821 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
@@ -15,8 +15,8 @@
 			<property name="hibernate.connection.driver_class" value="org.h2.Driver" />
 			<property name="hibernate.connection.url" value="jdbc:h2:mem:test-keycloak-photoz-example" />
 			<property name="hibernate.connection.user" value="sa" />
-			<property name="hibernate.flushMode" value="FLUSH_AUTO" />
-			<property name="hibernate.hbm2ddl.auto" value="update" />
+			<property name="hibernate.flushMode" value="COMMIT" />
+			<property name="hibernate.hbm2ddl.auto" value="create-drop" />
 			<property name="hibernate.show_sql" value="false" />
 		</properties>
 	</persistence-unit>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
index 34cf6bd..508bc72 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
@@ -1,41 +1,47 @@
 <?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">
+         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>photoz-restful-api</module-name>
+    <module-name>photoz-restful-api</module-name>
 
-	<security-constraint>
-		<web-resource-collection>
-			<web-resource-name>All Resources</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>All Resources</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>All Resources</web-resource-name>
-			<url-pattern>/*</url-pattern>
-		</web-resource-collection>
-		<auth-constraint>
-			<role-name>admin</role-name>
-		</auth-constraint>
-	</security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>All Resources</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Unsecured</web-resource-name>
+            <url-pattern>/unsecured/*</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
 
-	<login-config>
-		<auth-method>KEYCLOAK</auth-method>
-		<realm-name>photoz</realm-name>
-	</login-config>
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>photoz</realm-name>
+    </login-config>
 
-	<security-role>
-		<role-name>admin</role-name>
-	</security-role>
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
 
-	<security-role>
-		<role-name>user</role-name>
-	</security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
 </web-app>
diff --git a/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json b/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json
index 073dd80..bad1b25 100644
--- a/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json
+++ b/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json
@@ -107,6 +107,14 @@
                     {
                         "name": "Pattern 12",
                         "uri": "/realm_uri"
+                    },
+                    {
+                        "name": "Pattern 13",
+                        "uri": "/keycloak-6623/*"
+                    },
+                    {
+                        "name": "Pattern 14",
+                        "uri": "/keycloak-6623/sub-resource/*"
                     }
                 ],
                 "policies": [
@@ -258,6 +266,26 @@
                             "resources": "[\"Pattern 12\"]",
                             "applyPolicies": "[\"Default Policy\"]"
                         }
+                    },
+                    {
+                        "name": "Pattern 13 Permission",
+                        "type": "resource",
+                        "logic": "POSITIVE",
+                        "decisionStrategy": "UNANIMOUS",
+                        "config": {
+                            "resources": "[\"Pattern 13\"]",
+                            "applyPolicies": "[\"Default Policy\"]"
+                        }
+                    },
+                    {
+                        "name": "Pattern 14 Permission",
+                        "type": "resource",
+                        "logic": "POSITIVE",
+                        "decisionStrategy": "UNANIMOUS",
+                        "config": {
+                            "resources": "[\"Pattern 14\"]",
+                            "applyPolicies": "[\"Default Policy\"]"
+                        }
                     }
                 ],
                 "scopes": []
diff --git a/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json b/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json
index 1dfcd7b..0dd6a14 100644
--- a/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json
+++ b/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json
@@ -60,6 +60,14 @@
             {
                 "name": "Pattern 12",
                 "path": "/keycloak_json_uri"
+            },
+            {
+              "name": "Pattern 14",
+              "path": "/keycloak-6623/sub-resource/*"
+            },
+            {
+              "name": "Pattern 13",
+              "path": "/keycloak-6623/*"
             }
         ]
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java
index 1f61268..f87d481 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java
@@ -27,10 +27,11 @@ import org.keycloak.testsuite.util.URLUtils;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
-import org.openqa.selenium.support.ui.Select;
 
 import java.net.URL;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
 import static org.keycloak.testsuite.util.WaitUtils.pause;
 import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
 import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
@@ -82,12 +83,26 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
     }
 
     public void createAlbum(String name, String buttonId) {
+        log.debugf("Creating album {0} with buttonId: {1}", name, buttonId);
         navigateTo();
-        this.driver.findElement(By.id("create-album")).click();
-        Form.setInputValue(this.driver.findElement(By.id("album.name")), name);
+        WebElement createAlbum = driver.findElement(By.id("create-album"));
+        waitUntilElement(createAlbum).is().clickable();
+        createAlbum.click();
+        WebElement albumNameInput = driver.findElement(By.id("album.name"));
+        waitUntilElement(albumNameInput).is().present();
+        Form.setInputValue(albumNameInput, name);
         pause(200); // We need to wait a bit for the form to "accept" the input (otherwise it registers the input as empty)
-        this.driver.findElement(By.id(buttonId)).click();
+        waitUntilElement(albumNameInput).attribute(Form.VALUE).contains(name);
+        WebElement button = driver.findElement(By.id(buttonId));
+        waitUntilElement(button).is().clickable();
+        button.click();
         pause(WAIT_AFTER_OPERATION);
+        if (buttonId.equals("save-album-invalid")) {
+            waitForPageToLoad();
+            assertThat(driver.getPageSource(), containsString("Could not register protected resource."));
+        } else {
+            waitUntilElement(albumNameInput).is().not().present();
+        }
     }
 
     public void createAlbumWithInvalidUser(String name) {
@@ -99,32 +114,51 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
         return this.url;
     }
 
-    public void deleteAlbum(String name) {
-        driver.findElements(By.xpath("//a[text()='" + name + "']/following-sibling::a[text()='X']")).forEach(WebElement::click);
+    public void deleteAlbum(String name, boolean shouldBeDenied) {
+        log.debugf("Deleting album {0}", name);
+        WebElement delete = driver.findElement(By.id("delete-" + name));
+        waitUntilElement(delete).is().clickable();
+        delete.click();
         pause(WAIT_AFTER_OPERATION);
+        if (shouldBeDenied) {
+            waitForDenial();
+        } else {
+            waitUntilElement(delete).is().not().present();
+        }
     }
 
-    public void navigateToAdminAlbum() {
+    public void navigateToAdminAlbum(boolean shouldBeDenied) {
+        log.debug("Navigating to Admin Album");
         URLUtils.navigateToUri(toString() + "/#/admin/album", true);
+        
         driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
         waitForPageToLoad();
         pause(WAIT_AFTER_OPERATION);
+        if (shouldBeDenied) {
+            waitForDenial();
+        } else {
+            waitUntilElement(output).text().equalTo("");
+        }
     }
 
     public void logOut() {
-        waitUntilElement(signOutButton); // Sometimes doesn't work in PhantomJS!
+        waitUntilElement(signOutButton).is().clickable(); // Sometimes doesn't work in PhantomJS!
         signOutButton.click();
         pause(WAIT_AFTER_OPERATION);
     }
     
     public void requestEntitlement() {
+        waitUntilElement(entitlement).is().clickable();
         entitlement.click();
+        waitForPageToLoad();
         pause(WAIT_AFTER_OPERATION);
         pause(WAIT_AFTER_OPERATION);
     }
     
     public void requestEntitlements() {
+        waitUntilElement(entitlements).is().clickable();
         entitlements.click();
+        waitForPageToLoad();
         pause(WAIT_AFTER_OPERATION);
         pause(WAIT_AFTER_OPERATION);
     }
@@ -168,7 +202,8 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
         }
 
         this.loginPage.form().login(username, password);
-
+        waitForPageToLoad();//guess
+        
         // simple check if we are at the consent page, if so just click 'Yes'
         if (this.consentPage.isCurrent()) {
             consentPage.confirm();
@@ -177,12 +212,8 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
         pause(WAIT_AFTER_OPERATION);
     }
 
-    public boolean wasDenied() {
-        return this.driver.findElement(By.id("output")).getText().contains("You can not access");
-    }
-
-    public void viewAlbum(String name) throws InterruptedException {
-        viewAlbum(name, true);
+    private void waitForDenial() {
+        waitUntilElement(output).text().contains("You can not access");
     }
 
     public void viewAllAlbums() {
@@ -190,83 +221,130 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
         pause(WAIT_AFTER_OPERATION);
     }
 
-    public void viewAlbum(String name, boolean refresh) throws InterruptedException {
-        this.driver.findElement(By.xpath("//a[text() = '" + name + "']")).click();
+    public void viewAlbum(String name, boolean shouldBeDenied) {
+        WebElement viewalbum = driver.findElement(By.xpath("//a[text() = '" + name + "']"));
+        waitUntilElement(viewalbum).is().clickable();
+        viewalbum.click();
+        waitForPageToLoad();
+        if (shouldBeDenied) waitForDenial();
+        driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
         waitForPageToLoad();
-        if (refresh) {
-            driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
-        }
         pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountPage() throws InterruptedException {
+    public void accountPage() {
         navigateTo();
-        this.driver.findElement(By.id("my-account")).click();
+        WebElement myAccount = driver.findElement(By.id("my-account"));
+        waitUntilElement(myAccount).is().clickable();
+        myAccount.click();
+        waitForPageToLoad();
         pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountMyResources() throws InterruptedException {
+    public void accountMyResources() {
         accountPage();
-        this.driver.findElement(By.xpath("//a[text() = 'My Resources']")).click();
+        WebElement myResources = driver.findElement(By.xpath("//a[text() = 'My Resources']"));
+        waitUntilElement(myResources).is().clickable();
+        myResources.click();
         waitForPageToLoad();
         pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountMyResource(String name) throws InterruptedException {
+    public void accountMyResource(String name) {
         accountMyResources();
-        this.driver.findElement(By.id("detail-" + name)).click();
+        WebElement myResource = driver.findElement(By.id("detail-" + name));
+        waitUntilElement(myResource).is().clickable();
+        myResource.click();
         waitForPageToLoad();
         pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountGrantResource(String name, String requester) throws InterruptedException {
+    public void accountGrantResource(String name, String requester) {
         accountMyResources();
-        this.driver.findElement(By.id("grant-" + name + "-" + requester)).click();
+        WebElement grantResource = driver.findElement(By.id("grant-" + name + "-" + requester));
+        waitUntilElement(grantResource).is().clickable();
+        grantResource.click();
         waitForPageToLoad();
+        pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountGrantRemoveScope(String name, String requester, String scope) throws InterruptedException {
+    public void accountGrantRemoveScope(String name, String requester, String scope) {
         accountMyResources();
-        this.driver.findElement(By.id("grant-remove-scope-" + name + "-" + requester + "-" + scope)).click();
+        WebElement grantRemoveScope = driver.findElement(By.id("grant-remove-scope-" + name + "-" + requester + "-" + scope));
+        waitUntilElement(grantRemoveScope).is().clickable();
+        grantRemoveScope.click();
         waitForPageToLoad();
+        pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountRevokeResource(String name, String requester) throws InterruptedException {
+    public void accountRevokeResource(String name, String requester) {
         accountMyResource(name);
-        this.driver.findElement(By.id("revoke-" + name + "-" + requester)).click();
+        WebElement revokeResource = driver.findElement(By.id("revoke-" + name + "-" + requester));
+        waitUntilElement(revokeResource).is().clickable();
+        revokeResource.click();
         waitForPageToLoad();
+        pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountShareResource(String name, String user) throws InterruptedException {
+    public void accountShareResource(String name, String user) {
         accountMyResource(name);
-        this.driver.findElement(By.id("user_id")).sendKeys(user);
-        this.driver.findElement(By.id("share-button")).click();
+        WebElement userIdInput = driver.findElement(By.id("user_id"));
+        Form.setInputValue(userIdInput, user);
+        pause(200); // We need to wait a bit for the form to "accept" the input (otherwise it registers the input as empty)
+        waitUntilElement(userIdInput).attribute(Form.VALUE).contains(user);
+        
+        WebElement shareButton = driver.findElement(By.id("share-button"));
+        waitUntilElement(shareButton).is().clickable();
+        shareButton.click();
         waitForPageToLoad();
+        pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountShareRemoveScope(String name, String user, String scope) throws InterruptedException {
+    public void accountShareRemoveScope(String name, String user, String scope) {
         accountMyResource(name);
-        this.driver.findElement(By.id("user_id")).sendKeys(user);
-        this.driver.findElement(By.id("share-remove-scope-" + name + "-" + scope)).click();
-        this.driver.findElement(By.id("share-button")).click();
+        
+        WebElement userIdInput = driver.findElement(By.id("user_id"));
+        Form.setInputValue(userIdInput, user);
+        pause(200); // We need to wait a bit for the form to "accept" the input (otherwise it registers the input as empty)
+        waitUntilElement(userIdInput).attribute(Form.VALUE).contains(user);
+        
+        WebElement shareRemoveScope = driver.findElement(By.id("share-remove-scope-" + name + "-" + scope));
+        waitUntilElement(shareRemoveScope).is().clickable();
+        shareRemoveScope.click();
         waitForPageToLoad();
+        
+        WebElement shareButton = driver.findElement(By.id("share-button"));
+        waitUntilElement(shareButton).is().clickable();
+        shareButton.click();
+        
+        waitForPageToLoad();
+        pause(WAIT_AFTER_OPERATION);
     }
 
-    public void accountDenyResource(String name) throws InterruptedException {
+    public void accountDenyResource(String name) {
         accountMyResource(name);
-        this.driver.findElement(By.xpath("//a[text() = 'Deny']")).click();
+        WebElement denyLink = driver.findElement(By.linkText("Deny"));
+        waitUntilElement(denyLink).is().clickable();
+        denyLink.click();
         waitForPageToLoad();
+        pause(WAIT_AFTER_OPERATION);
     }
 
-    public void requestResourceProtectedAnyScope() throws InterruptedException {
+    public void requestResourceProtectedAnyScope(boolean shouldBeDenied) {
         navigateTo();
-        this.driver.findElement(By.id("requestPathWithAnyProtectedScope")).click();
+        WebElement requestPathWithAnyProtectedScope = driver.findElement(By.id("requestPathWithAnyProtectedScope"));
+        waitUntilElement(requestPathWithAnyProtectedScope).is().clickable();
+        requestPathWithAnyProtectedScope.click();
+        if (shouldBeDenied) waitForDenial();
         pause(WAIT_AFTER_OPERATION);
     }
 
-    public void requestResourceProtectedAllScope() throws InterruptedException {
+    public void requestResourceProtectedAllScope(boolean shouldBeDenied) {
         navigateTo();
-        this.driver.findElement(By.id("requestPathWithAllProtectedScope")).click();
+        WebElement requestPathWithAllProtectedScope = driver.findElement(By.id("requestPathWithAllProtectedScope"));
+        waitUntilElement(requestPathWithAllProtectedScope).is().clickable();
+        requestPathWithAllProtectedScope.click();
+        if (shouldBeDenied) waitForDenial();
         pause(WAIT_AFTER_OPERATION);
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java
index f2f5528..fb0aa3d 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java
@@ -17,7 +17,10 @@
 
 package org.keycloak.testsuite.drone;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
@@ -25,9 +28,11 @@ import org.jboss.arquillian.drone.spi.Configurator;
 import org.jboss.arquillian.drone.spi.DronePoint;
 import org.jboss.arquillian.drone.webdriver.configuration.WebDriverConfiguration;
 import org.jboss.arquillian.drone.webdriver.factory.BrowserCapabilitiesList;
+import org.jboss.arquillian.drone.webdriver.factory.BrowserCapabilitiesList.PhantomJS;
 import org.jboss.arquillian.drone.webdriver.factory.WebDriverFactory;
 import org.jboss.logging.Logger;
 import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.phantomjs.PhantomJSDriverService;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -47,11 +52,36 @@ public class KeycloakWebDriverConfigurator extends WebDriverFactory implements C
 
         if (webDriverCfg.getBrowser().equals("htmlUnit")) {
             updateCapabilities(webDriverCfg);
+        } else if (webDriverCfg.getBrowser().equals("phantomjs")) {
+            configurePhantomJSDriver(webDriverCfg);
         }
 
         return webDriverCfg;
     }
 
+    private void configurePhantomJSDriver(WebDriverConfiguration webDriverCfg) {
+        webDriverCfg.setBrowserInternal(new PhantomJS() {
+            @Override
+            public Map<String, ?> getRawCapabilities() {
+                List<String> cliArgs = new ArrayList<>();
+                String cliArgsProperty = System.getProperty("keycloak.phantomjs.cli.args");
+
+                if (cliArgsProperty != null) {
+                    cliArgs = Arrays.asList(cliArgsProperty.split(" "));
+                } else {
+                    cliArgs.add("--ignore-ssl-errors=true");
+                    cliArgs.add("--web-security=false");
+                }
+
+                Map<String, Object> mergedCapabilities = new HashMap<>(super.getRawCapabilities());
+
+                mergedCapabilities.put(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cliArgs.toArray(new String[cliArgs.size()]));
+
+                return mergedCapabilities;
+            }
+        });
+    }
+
 
     // This is to ensure that default value of capabilities like "version" will be used just for the HtmlUnitDriver, but not for other drivers.
     // Hence in configs we have "htmlUnit.version" instead of "version"
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java
index bb6f4ea..5a9ea86 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.testsuite.pages.social;
 
+import org.keycloak.testsuite.util.WaitUtils;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
@@ -35,9 +36,12 @@ public class MicrosoftLoginPage extends AbstractSocialLoginPage {
 
     @Override
     public void login(String user, String password) {
+        WaitUtils.pause(5000); // we need to take it a bit slower
         usernameInput.clear();
         usernameInput.sendKeys(user);
         submitButton.click();
+
+        WaitUtils.pause(5000);
         passwordInput.sendKeys(password);
         submitButton.click();
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
index 84691be..ff8546c 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
@@ -122,6 +122,11 @@ public class SamlClient {
             }
 
             @Override
+            public HttpUriRequest createSamlSignedResponse(URI samlEndpoint, String relayState, Document samlRequest, String realmPrivateKey, String realmPublicKey) {
+                return null;
+            }
+
+            @Override
             public HttpPost createSamlSignedRequest(URI samlEndpoint, String relayState, Document samlRequest, String realmPrivateKey, String realmPublicKey) {
                 return createSamlPostMessage(samlEndpoint, relayState, samlRequest, GeneralConstants.SAML_REQUEST_KEY, realmPrivateKey, realmPublicKey);
             }
@@ -206,7 +211,38 @@ public class SamlClient {
 
             @Override
             public HttpUriRequest createSamlUnsignedResponse(URI samlEndpoint, String relayState, Document samlRequest) {
-                return null;
+                try {
+                    URI responseURI = new BaseSAML2BindingBuilder()
+                            .relayState(relayState)
+                            .redirectBinding(samlRequest)
+                            .responseURI(samlEndpoint.toString());
+                    return new HttpGet(responseURI);
+                } catch (ProcessingException | ConfigurationException | IOException ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+
+            @Override
+            public HttpUriRequest createSamlSignedResponse(URI samlEndpoint, String relayState, Document samlRequest, String realmPrivateKey, String realmPublicKey) {
+
+                try {
+                    BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder();
+
+                    if (realmPrivateKey != null && realmPublicKey != null) {
+                        PrivateKey privateKey = org.keycloak.testsuite.util.KeyUtils.privateKeyFromString(realmPrivateKey);
+                        PublicKey publicKey = org.keycloak.testsuite.util.KeyUtils.publicKeyFromString(realmPublicKey);
+                        binding
+                                .signatureAlgorithm(SignatureAlgorithm.RSA_SHA256)
+                                .signWith(KeyUtils.createKeyId(privateKey), privateKey, publicKey)
+                                .signDocument();
+                    }
+
+                    binding.relayState(relayState);
+
+                    return new HttpGet(binding.redirectBinding(samlRequest).responseURI(samlEndpoint.toString()));
+                } catch (IOException | ConfigurationException | ProcessingException ex) {
+                    throw new RuntimeException(ex);
+                }
             }
 
             @Override
@@ -224,6 +260,8 @@ public class SamlClient {
         public abstract URI getBindingUri();
 
         public abstract HttpUriRequest createSamlUnsignedResponse(URI samlEndpoint, String relayState, Document samlRequest);
+
+        public abstract HttpUriRequest createSamlSignedResponse(URI samlEndpoint, String relayState, Document samlRequest, String realmPrivateKey, String realmPublicKey);
     }
 
     private static final Logger LOG = Logger.getLogger(SamlClient.class);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java
index a7cded4..4cc9d4a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java
@@ -16,7 +16,11 @@
  */
 package org.keycloak.testsuite.adapter.example.authorization;
 
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.keycloak.testsuite.util.IOUtil.loadJson;
 import static org.keycloak.testsuite.util.IOUtil.loadRealm;
@@ -31,14 +35,18 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.LaxRedirectStrategy;
 
 import org.jboss.arquillian.container.test.api.Deployer;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.graphene.page.Page;
 import org.jboss.arquillian.test.api.ArquillianResource;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -68,7 +76,7 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
 
     private static final String REALM_NAME = "photoz";
     private static final String RESOURCE_SERVER_ID = "photoz-restful-api";
-    private static int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
+    private static final int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
 
     @ArquillianResource
     private Deployer deployer;
@@ -86,8 +94,19 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
     public static void enabled() { ProfileAssume.assumePreview(); }
 
     @Before
-    public void beforePhotozExampleAdapterTest() throws FileNotFoundException {
+    public void beforePhotozExampleAdapterTest() throws Exception {
         deleteAllCookiesForClientPage();
+        this.deployer.deploy(RESOURCE_SERVER_ID);
+        
+        try (CloseableHttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build()) {
+            HttpGet request = new HttpGet(clientPage.toString() + "/unsecured/clean");
+            httpClient.execute(request).close();
+        } 
+    }
+    
+    @After
+    public void afterPhotozExampleAdapterTest() {
+        this.deployer.undeploy(RESOURCE_SERVER_ID);
     }
 
     @Override
@@ -115,655 +134,530 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
         importResourceServerSettings();
     }
 
+    private List<ResourceRepresentation> getResourcesOfUser(String username) throws FileNotFoundException {
+        return getAuthorizationResource().resources().resources().stream().filter(resource -> resource.getOwner().getName().equals(username)).collect(Collectors.toList());
+    }
+    
+    private void printUpdatedPolicies() throws FileNotFoundException {
+        log.debug("Check updated policies");
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            log.debugf("Policy: {0}", policy.getName());
+            for (String key : policy.getConfig().keySet()) {
+                log.debugf("-- key: {0}, value: {1}", key, policy.getConfig().get(key));
+            }
+        }
+        log.debug("------------------------------");
+    }
+    
     @Test
     public void testUserCanCreateAndDeleteAlbum() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice Family Album");
+        loginToClientPage("alice", "alice");
 
-            List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
-            assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        clientPage.createAlbum("Alice Family Album");
+        log.debug("Check if alice has resources stored");
+        assertThat(getResourcesOfUser("alice"), is(not(empty())));
 
-            this.clientPage.deleteAlbum("Alice Family Album");
-
-            resources = getAuthorizationResource().resources().resources();
-            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        clientPage.deleteAlbum("Alice Family Album", false);
+        log.debug("Check if alice has resources deleted");
+        assertThat(getResourcesOfUser("alice"), is(empty()));
     }
 
     @Test
     public void createAlbumWithInvalidUser() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
+        loginToClientPage("alice", "alice");
 
-            loginToClientPage("alice", "alice");
+        clientPage.createAlbumWithInvalidUser("Alice Family Album");
 
-            clientPage.createAlbumWithInvalidUser("Alice Family Album");
-
-            waitUntilElement(clientPage.getOutput()).text().not().contains("Request was successful");
-            waitUntilElement(clientPage.getOutput()).text().contains("Could not register protected resource");
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        log.debug("Check if the album was not created.");
+        waitUntilElement(clientPage.getOutput()).text().not().contains("Request was successful");
+        waitUntilElement(clientPage.getOutput()).text().contains("Could not register protected resource");
     }
 
     @Test
     public void testOnlyOwnerCanDeleteAlbum() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice-Family-Album");
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice-Family-Album");
 
-            loginToClientPage("admin", "admin");
-            this.clientPage.navigateToAdminAlbum();
+        loginToClientPage("admin", "admin");
+        clientPage.navigateToAdminAlbum(false);
 
-            List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
-            assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        log.debug("Check if alice has resources stored");
+        assertThat(getResourcesOfUser("alice"), is(not(empty())));
 
-            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
-                if ("Delete Album Permission".equals(policy.getName())) {
-                    policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
+        log.debug("Adding applyPolicies \"Only Owner Policy\" to \"Delete Album Permission\" policies.");
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            if ("Delete Album Permission".equals(policy.getName())) {
+                policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
             }
+        }
+        printUpdatedPolicies();
 
-            loginToClientPage("admin", "admin");
+        loginToClientPage("admin", "admin");
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.deleteAlbum("Alice-Family-Album");
-            assertTrue(this.clientPage.wasDenied());
-            resources = getAuthorizationResource().resources().resources();
-            assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum("Alice-Family-Album", true);
+        
+        log.debug("Check if alice has resources stored");
+        assertThat(getResourcesOfUser("alice"), is(not(empty())));
 
-            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
-                if ("Delete Album Permission".equals(policy.getName())) {
-                    policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
+        log.debug("Adding applyPolicies \"Only Owner and Administrators Policy\" to \"Delete Album Permission\" policies.");
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            if ("Delete Album Permission".equals(policy.getName())) {
+                policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
             }
-
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.deleteAlbum("Alice-Family-Album");
-            assertFalse(this.clientPage.wasDenied());
-            resources = getAuthorizationResource().resources().resources();
-            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
         }
-    }
+        printUpdatedPolicies();
 
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum("Alice-Family-Album", false);
+        
+        log.debug("Check if alice has resources deleted");
+        assertThat(getResourcesOfUser("alice"), is(empty()));
+    }
+ 
+    
     @Test
     public void testRegularUserCanNotAccessAdminResources() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.navigateToAdminAlbum();
-            assertTrue(this.clientPage.wasDenied());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        loginToClientPage("alice", "alice");
+        clientPage.navigateToAdminAlbum(true);
     }
 
     @Test
     public void testAdminOnlyFromSpecificAddress() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("admin", "admin");
-            this.clientPage.navigateToAdminAlbum();
-            assertFalse(this.clientPage.wasDenied());
-
-            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
-                if ("Only From a Specific Client Address".equals(policy.getName())) {
-                    String code = policy.getConfig().get("code");
-                    policy.getConfig().put("code", code.replaceAll("127.0.0.1", "127.3.3.3"));
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
+        loginToClientPage("admin", "admin");
+        clientPage.navigateToAdminAlbum(false);
+
+        log.debug("Changing codes \"127.0.0.1\" to \"127.3.3.3\" of \"Only From a Specific Client Address\" policies.");
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            if ("Only From a Specific Client Address".equals(policy.getName())) {
+                String code = policy.getConfig().get("code");
+                policy.getConfig().put("code", code.replaceAll("127.0.0.1", "127.3.3.3"));
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
             }
-
-            this.clientPage.navigateToAdminAlbum();
-            assertTrue(this.clientPage.wasDenied());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
         }
+        printUpdatedPolicies();
+
+        clientPage.navigateToAdminAlbum(true);
     }
 
     @Test
     public void testAdminWithoutPermissionsToTypedResource() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice Family Album");
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice Family Album");
+        
+        loginToClientPage("admin", "admin");
+        clientPage.navigateToAdminAlbum(false);
+
+        clientPage.viewAlbum("Alice Family Album", false);
+
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            if ("Album Resource Permission".equals(policy.getName())) {
+                policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+            }
+            if ("Any User Policy".equals(policy.getName())) {
+                ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+                RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
+                RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
+                List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
 
-            loginToClientPage("admin", "admin");
-            this.clientPage.navigateToAdminAlbum();
-            assertFalse(this.clientPage.wasDenied());
+                roles = roles.stream().filter((Map map) -> !map.get("id").equals(roleRepresentation.getId())).collect(Collectors.toList());
 
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertFalse(this.clientPage.wasDenied());
+                policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
 
-            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
-                if ("Album Resource Permission".equals(policy.getName())) {
-                    policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
-                if ("Any User Policy".equals(policy.getName())) {
-                    ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
-                    RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
-                    RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
-                    List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
-
-                    roles = roles.stream().filter(new Predicate<Map>() {
-                        @Override
-                        public boolean test(Map map) {
-                            return !map.get("id").equals(roleRepresentation.getId());
-                        }
-                    }).collect(Collectors.toList());
-
-                    policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
-
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
             }
+        }
+        printUpdatedPolicies();
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertTrue(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.viewAlbum("Alice Family Album", true);
 
-            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
-                if ("Album Resource Permission".equals(policy.getName())) {
-                    policy.getConfig().put("applyPolicies", "[\"Any User Policy\", \"Administration Policy\"]");
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            if ("Album Resource Permission".equals(policy.getName())) {
+                policy.getConfig().put("applyPolicies", "[\"Any User Policy\", \"Administration Policy\"]");
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
             }
+        }
+        printUpdatedPolicies();
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.viewAlbum("Alice Family Album", false);
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.deleteAlbum("Alice Family Album");
-            List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
-            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum("Alice Family Album", false);
+        assertThat(getResourcesOfUser("alice"), is(empty()));
     }
 
     @Test
     public void testAdminWithoutPermissionsToDeleteAlbum() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice Family Album");
-
-            loginToClientPage("admin", "admin");
-            this.clientPage.navigateToAdminAlbum();
-            assertFalse(this.clientPage.wasDenied());
-
-            this.clientPage.deleteAlbum("Alice Family Album");
-            assertFalse(this.clientPage.wasDenied());
-            List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
-            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
-
-            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
-                if ("Delete Album Permission".equals(policy.getName())) {
-                    policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice Family Album");
+
+        loginToClientPage("admin", "admin");
+        clientPage.navigateToAdminAlbum(false);
+
+        clientPage.deleteAlbum("Alice Family Album", false);
+        assertThat(getResourcesOfUser("alice"), is(empty()));
+        
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            if ("Delete Album Permission".equals(policy.getName())) {
+                policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
             }
+        }
+        printUpdatedPolicies();
 
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice Family Album");
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice Family Album");
 
-            loginToClientPage("admin", "admin");
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertFalse(this.clientPage.wasDenied());
-            resources = getAuthorizationResource().resources().resources();
-            assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        loginToClientPage("admin", "admin");
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.viewAlbum("Alice Family Album", false);
+        assertThat(getResourcesOfUser("alice"), is(not(empty())));
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.deleteAlbum("Alice Family Album");
-            assertTrue(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum("Alice Family Album", true);
 
-            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
-                if ("Delete Album Permission".equals(policy.getName())) {
-                    policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            if ("Delete Album Permission".equals(policy.getName())) {
+                policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
             }
-
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.deleteAlbum("Alice Family Album");
-            assertFalse(this.clientPage.wasDenied());
-            resources = getAuthorizationResource().resources().resources();
-            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
         }
+        printUpdatedPolicies();
+
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum("Alice Family Album", false);
+        assertThat(getResourcesOfUser("alice"), is(empty()));
     }
 
     @Test
     public void testClientRoleRepresentingUserConsent() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("alice", "alice");
-            assertFalse(this.clientPage.wasDenied());
-            this.clientPage.createAlbum("Alice Family Album");
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertFalse(this.clientPage.wasDenied());
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice Family Album");
+        clientPage.viewAlbum("Alice Family Album", false);
 
-            UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
-            List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
+        UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
+        List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
 
-            assertFalse(users.isEmpty());
+        assertFalse(users.isEmpty());
 
-            UserRepresentation userRepresentation = users.get(0);
-            UserResource userResource = usersResource.get(userRepresentation.getId());
+        UserRepresentation userRepresentation = users.get(0);
+        UserResource userResource = usersResource.get(userRepresentation.getId());
 
-            ClientResource html5ClientApp = getClientResource("photoz-html5-client");
+        ClientResource html5ClientApp = getClientResource("photoz-html5-client");
 
-            userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
+        userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
 
-            ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
-            RoleResource roleResource = resourceServerClient.roles().get("manage-albums");
-            RoleRepresentation roleRepresentation = roleResource.toRepresentation();
+        ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+        RoleResource roleResource = resourceServerClient.roles().get("manage-albums");
+        RoleRepresentation roleRepresentation = roleResource.toRepresentation();
 
-            roleRepresentation.setScopeParamRequired(true);
+        roleRepresentation.setScopeParamRequired(true);
 
-            roleResource.update(roleRepresentation);
+        roleResource.update(roleRepresentation);
 
-            loginToClientPage("alice", "alice");
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertTrue(this.clientPage.wasDenied());
+        loginToClientPage("alice", "alice");
+        clientPage.viewAlbum("Alice Family Album", true);
 
-            loginToClientPage("alice", "alice", RESOURCE_SERVER_ID + "/manage-albums");
-            this.clientPage.viewAlbum("Alice Family Album", false);
-            assertFalse(this.clientPage.wasDenied());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        loginToClientPage("alice", "alice", RESOURCE_SERVER_ID + "/manage-albums");
+        clientPage.viewAlbum("Alice Family Album", false);
     }
 
     @Test
     public void testClientRoleNotRequired() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("alice", "alice");
+        loginToClientPage("alice", "alice");
 
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.createAlbum("Alice Family Album");
+        clientPage.viewAlbum("Alice Family Album", false);
 
-            this.clientPage.createAlbum("Alice Family Album");
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertFalse(this.clientPage.wasDenied());
+        UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
+        List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
 
-            UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
-            List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
+        assertFalse(users.isEmpty());
 
-            assertFalse(users.isEmpty());
+        UserRepresentation userRepresentation = users.get(0);
+        UserResource userResource = usersResource.get(userRepresentation.getId());
 
-            UserRepresentation userRepresentation = users.get(0);
-            UserResource userResource = usersResource.get(userRepresentation.getId());
+        ClientResource html5ClientApp = getClientResource("photoz-html5-client");
 
-            ClientResource html5ClientApp = getClientResource("photoz-html5-client");
+        userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
 
-            userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
+        ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+        RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
+        RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
 
-            ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
-            RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
-            RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
+        roleRepresentation.setScopeParamRequired(true);
 
-            roleRepresentation.setScopeParamRequired(true);
+        manageAlbumRole.update(roleRepresentation);
 
-            manageAlbumRole.update(roleRepresentation);
+        loginToClientPage("alice", "alice");
+        clientPage.viewAlbum("Alice Family Album", true);
 
-            loginToClientPage("alice", "alice");
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertTrue(this.clientPage.wasDenied());
+        for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+            if ("Any User Policy".equals(policy.getName())) {
+                List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
 
-            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
-                if ("Any User Policy".equals(policy.getName())) {
-                    List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
-
-                    roles.forEach(role -> {
-                        String roleId = (String) role.get("id");
-                        if (roleId.equals(manageAlbumRole.toRepresentation().getId())) {
-                            role.put("required", false);
-                        }
-                    });
+                roles.forEach(role -> {
+                    String roleId = (String) role.get("id");
+                    if (roleId.equals(manageAlbumRole.toRepresentation().getId())) {
+                        role.put("required", false);
+                    }
+                });
 
-                    policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
-                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
-                }
+                policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
+                getAuthorizationResource().policies().policy(policy.getId()).update(policy);
             }
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.viewAlbum("Alice Family Album");
-            assertFalse(this.clientPage.wasDenied());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
         }
+        printUpdatedPolicies();
+
+        loginToClientPage("alice", "alice");
+        clientPage.viewAlbum("Alice Family Album", false);
     }
 
     @Test
     public void testOverridePermissionFromResourceParent() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("alice", "alice");
-            String resourceName = "My Resource Instance";
-            this.clientPage.createAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        loginToClientPage("alice", "alice");
+        String resourceName = "My Resource Instance";
+        clientPage.createAlbum(resourceName);
 
-            this.clientPage.viewAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.viewAlbum(resourceName, false);
 
-            this.clientPage.navigateTo();
-            this.clientPage.deleteAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.navigateTo();
+        clientPage.deleteAlbum(resourceName, false);
 
-            this.clientPage.createAlbum(resourceName);
+        clientPage.createAlbum(resourceName);
 
-            this.clientPage.logOut();
-            loginToClientPage("admin", "admin");
+        clientPage.logOut();
+        loginToClientPage("admin", "admin");
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.viewAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.viewAlbum(resourceName, false);
 
-            this.clientPage.navigateToAdminAlbum();;
-            this.clientPage.deleteAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum(resourceName, false);
 
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum(resourceName);
 
-            getAuthorizationResource().resources().resources().forEach(resource -> {
-                if (resource.getName().equals(resourceName)) {
-                    try {
-                        PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
+        getAuthorizationResource().resources().resources().forEach(resource -> {
+            if (resource.getName().equals(resourceName)) {
+                try {
+                    PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
 
-                        resourceInstancePermission.setName(resourceName + "Permission");
-                        resourceInstancePermission.setType("resource");
+                    resourceInstancePermission.setName(resourceName + "Permission");
+                    resourceInstancePermission.setType("resource");
 
-                        Map<String, String> config = new HashMap<>();
+                    Map<String, String> config = new HashMap<>();
 
-                        config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
-                        config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
+                    config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
+                    config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
 
-                        resourceInstancePermission.setConfig(config);
-                        getAuthorizationResource().policies().create(resourceInstancePermission);
-                    } catch (Exception e) {
-                        throw new RuntimeException("Error creating policy.", e);
-                    }
+                    resourceInstancePermission.setConfig(config);
+                    getAuthorizationResource().policies().create(resourceInstancePermission);
+                } catch (IOException e) {
+                    throw new RuntimeException("Error creating policy.", e);
                 }
-            });
+            }
+        });
+        printUpdatedPolicies();
 
-            loginToClientPage("admin", "admin");
+        loginToClientPage("admin", "admin");
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.viewAlbum(resourceName);
-            assertTrue(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.viewAlbum(resourceName, true);
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.deleteAlbum(resourceName);
-            assertTrue(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum(resourceName, true);
 
-            loginToClientPage("alice", "alice");
-            this.clientPage.deleteAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        loginToClientPage("alice", "alice");
+        clientPage.deleteAlbum(resourceName, false);
 
-            ResourcesResource resourcesResource = getAuthorizationResource().resources();
-            List<ResourceRepresentation> resources = resourcesResource.resources();
-            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        assertThat(getResourcesOfUser("alice"), is(empty()));
     }
 
     @Test
     public void testInheritPermissionFromResourceParent() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-
-            loginToClientPage("alice", "alice");
+        loginToClientPage("alice", "alice");
 
-            String resourceName = "My Resource Instance";
-            this.clientPage.createAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        String resourceName = "My Resource Instance";
+        clientPage.createAlbum(resourceName);
 
-            this.clientPage.viewAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.viewAlbum(resourceName, false);
 
-            this.clientPage.navigateTo();
-            this.clientPage.deleteAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.navigateTo();
+        clientPage.deleteAlbum(resourceName, false);
 
-            this.clientPage.createAlbum(resourceName);
+        clientPage.createAlbum(resourceName);
 
-            loginToClientPage("admin", "admin");
+        loginToClientPage("admin", "admin");
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.viewAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.viewAlbum(resourceName, false);
 
-            this.clientPage.navigateToAdminAlbum();;
-            this.clientPage.deleteAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum(resourceName, false);
 
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum(resourceName);
 
-            ResourcesResource resourcesResource = getAuthorizationResource().resources();
-            resourcesResource.resources().forEach(resource -> {
-                if (resource.getName().equals(resourceName)) {
-                    try {
-                        PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
+        ResourcesResource resourcesResource = getAuthorizationResource().resources();
+        resourcesResource.resources().forEach(resource -> {
+            if (resource.getName().equals(resourceName)) {
+                try {
+                    PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
 
-                        resourceInstancePermission.setName(resourceName + "Permission");
-                        resourceInstancePermission.setType("resource");
+                    resourceInstancePermission.setName(resourceName + "Permission");
+                    resourceInstancePermission.setType("resource");
 
-                        Map<String, String> config = new HashMap<>();
+                    Map<String, String> config = new HashMap<>();
 
-                        config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
-                        config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
+                    config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
+                    config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
 
-                        resourceInstancePermission.setConfig(config);
-                        getAuthorizationResource().policies().create(resourceInstancePermission);
-                    } catch (Exception e) {
-                        throw new RuntimeException("Error creating policy.", e);
-                    }
+                    resourceInstancePermission.setConfig(config);
+                    getAuthorizationResource().policies().create(resourceInstancePermission);
+                } catch (IOException e) {
+                    throw new RuntimeException("Error creating policy.", e);
                 }
-            });
+            }
+        });
 
-            loginToClientPage("admin", "admin");
+        loginToClientPage("admin", "admin");
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.viewAlbum(resourceName);
-            assertTrue(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.viewAlbum(resourceName, true);
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.deleteAlbum(resourceName);
-            assertTrue(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum(resourceName, true);
 
-            resourcesResource.resources().forEach(resource -> {
-                if (resource.getName().equals(resourceName)) {
-                    resource.setScopes(resource.getScopes().stream().filter(scope -> !scope.getName().equals("album:view")).collect(Collectors.toSet()));
-                    resourcesResource.resource(resource.getId()).update(resource);
-                }
-            });
+        resourcesResource.resources().forEach(resource -> {
+            if (resource.getName().equals(resourceName)) {
+                resource.setScopes(resource.getScopes().stream().filter(scope -> !scope.getName().equals("album:view")).collect(Collectors.toSet()));
+                resourcesResource.resource(resource.getId()).update(resource);
+            }
+        });
 
-            loginToClientPage("admin", "admin");
+        loginToClientPage("admin", "admin");
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.viewAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.viewAlbum(resourceName, false);
 
-            this.clientPage.navigateToAdminAlbum();
-            this.clientPage.deleteAlbum(resourceName);
-            assertTrue(this.clientPage.wasDenied());
+        clientPage.navigateToAdminAlbum(false);
+        clientPage.deleteAlbum(resourceName, true);
 
-            loginToClientPage("alice", "alice");
-            this.clientPage.deleteAlbum(resourceName);
-            assertFalse(this.clientPage.wasDenied());
-            List<ResourceRepresentation> resources = resourcesResource.resources();
-            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        loginToClientPage("alice", "alice");
+        clientPage.deleteAlbum(resourceName, false);
+        List<ResourceRepresentation> resources = resourcesResource.resources();
+        assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
 
-            resourcesResource.resources().forEach(resource -> {
-                if (resource.getName().equals(resourceName)) {
-                    resource.setScopes(Collections.emptySet());
-                    resourcesResource.resource(resource.getId()).update(resource);
-                }
-            });
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        resourcesResource.resources().forEach(resource -> {
+            if (resource.getName().equals(resourceName)) {
+                resource.setScopes(Collections.emptySet());
+                resourcesResource.resource(resource.getId()).update(resource);
+            }
+        });
     }
     
     //KEYCLOAK-3777
     @Test
     public void testEntitlementRequest() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-            
-            clientPage.navigateTo();
-            loginToClientPage("admin", "admin");
-
-            clientPage.requestEntitlements();
-            assertTrue(driver.getPageSource().contains("admin:manage"));
-            
-            clientPage.requestEntitlement();
-            String pageSource = driver.getPageSource();
-            assertTrue(pageSource.contains("album:view"));
-            assertTrue(pageSource.contains("album:delete"));
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        clientPage.navigateTo();
+        loginToClientPage("admin", "admin");
+
+        clientPage.requestEntitlements();
+        assertTrue(driver.getPageSource().contains("admin:manage"));
+
+        clientPage.requestEntitlement();
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("album:view"));
+        assertTrue(pageSource.contains("album:delete"));
     }
 
     @Test
     public void testResourceProtectedWithAnyScope() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-            loginToClientPage("alice", "alice");
-            this.clientPage.requestResourceProtectedAllScope();
-            assertTrue(this.clientPage.wasDenied());
-            this.clientPage.requestResourceProtectedAnyScope();
-            assertFalse(this.clientPage.wasDenied());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        loginToClientPage("alice", "alice");
+        clientPage.requestResourceProtectedAllScope(true);
+        clientPage.requestResourceProtectedAnyScope(false);
     }
 
     @Test
     public void testRequestResourceToOwner() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice-Family-Album", true);
-
-            loginToClientPage("jdoe", "jdoe");
-            this.clientPage.viewAllAlbums();
-            this.clientPage.viewAlbum("Alice-Family-Album");
-            assertTrue(this.clientPage.wasDenied());
-            this.clientPage.navigateTo();
-            this.clientPage.viewAllAlbums();
-            this.clientPage.deleteAlbum("Alice-Family-Album");
-            assertTrue(this.clientPage.wasDenied());
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.accountGrantResource("Alice-Family-Album", "jdoe");
-
-            loginToClientPage("jdoe", "jdoe");
-            this.clientPage.viewAllAlbums();
-            this.clientPage.viewAlbum("Alice-Family-Album");
-            assertFalse(this.clientPage.wasDenied());
-            this.clientPage.navigateTo();
-            this.clientPage.viewAllAlbums();
-            this.clientPage.deleteAlbum("Alice-Family-Album");
-            assertFalse(this.clientPage.wasDenied());
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice-Family-Album", true);
-
-            loginToClientPage("jdoe", "jdoe");
-            this.clientPage.viewAllAlbums();
-            this.clientPage.viewAlbum("Alice-Family-Album");
-            assertTrue(this.clientPage.wasDenied());
-            this.clientPage.navigateTo();
-            this.clientPage.viewAllAlbums();
-            this.clientPage.deleteAlbum("Alice-Family-Album");
-            assertTrue(this.clientPage.wasDenied());
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.accountGrantRemoveScope("Alice-Family-Album", "jdoe", "album:delete");
-            this.clientPage.accountGrantResource("Alice-Family-Album", "jdoe");
-
-            loginToClientPage("jdoe", "jdoe");
-            this.clientPage.viewAllAlbums();
-            this.clientPage.viewAlbum("Alice-Family-Album");
-            assertFalse(this.clientPage.wasDenied());
-            this.clientPage.navigateTo();
-            this.clientPage.viewAllAlbums();
-            this.clientPage.deleteAlbum("Alice-Family-Album");
-            assertTrue(this.clientPage.wasDenied());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice-Family-Album", true);
+
+        loginToClientPage("jdoe", "jdoe");
+        clientPage.viewAllAlbums();
+        clientPage.viewAlbum("Alice-Family-Album", true);
+        clientPage.navigateTo();
+        clientPage.viewAllAlbums();
+        clientPage.deleteAlbum("Alice-Family-Album", true);
+
+        loginToClientPage("alice", "alice");
+        clientPage.accountGrantResource("Alice-Family-Album", "jdoe");
+
+        loginToClientPage("jdoe", "jdoe");
+        clientPage.viewAllAlbums();
+        clientPage.viewAlbum("Alice-Family-Album", false);
+        clientPage.navigateTo();
+        clientPage.viewAllAlbums();
+        clientPage.deleteAlbum("Alice-Family-Album", false);
+
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice-Family-Album", true);
+
+        loginToClientPage("jdoe", "jdoe");
+        clientPage.viewAllAlbums();
+        clientPage.viewAlbum("Alice-Family-Album", true);
+        clientPage.navigateTo();
+        clientPage.viewAllAlbums();
+        clientPage.deleteAlbum("Alice-Family-Album", true);
+
+        loginToClientPage("alice", "alice");
+        clientPage.accountGrantRemoveScope("Alice-Family-Album", "jdoe", "album:delete");
+        clientPage.accountGrantResource("Alice-Family-Album", "jdoe");
+
+        loginToClientPage("jdoe", "jdoe");
+        clientPage.viewAllAlbums();
+        clientPage.viewAlbum("Alice-Family-Album", false);
+        clientPage.navigateTo();
+        clientPage.viewAllAlbums();
+        clientPage.deleteAlbum("Alice-Family-Album", true);
     }
 
     @Test
     public void testOwnerSharingResource() throws Exception {
-        try {
-            this.deployer.deploy(RESOURCE_SERVER_ID);
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice-Family-Album", true);
-            this.clientPage.accountShareResource("Alice-Family-Album", "jdoe");
-
-            loginToClientPage("jdoe", "jdoe");
-            this.clientPage.viewAllAlbums();
-            this.clientPage.viewAlbum("Alice-Family-Album");
-            assertFalse(this.clientPage.wasDenied());
-            this.clientPage.navigateTo();
-            this.clientPage.viewAllAlbums();
-            this.clientPage.deleteAlbum("Alice-Family-Album");
-            assertFalse(this.clientPage.wasDenied());
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.createAlbum("Alice-Family-Album", true);
-            this.clientPage.accountShareRemoveScope("Alice-Family-Album", "jdoe", "album:delete");
-
-            loginToClientPage("jdoe", "jdoe");
-            this.clientPage.viewAllAlbums();
-            this.clientPage.viewAlbum("Alice-Family-Album");
-            assertFalse(this.clientPage.wasDenied());
-            this.clientPage.navigateTo();
-            this.clientPage.viewAllAlbums();
-            this.clientPage.deleteAlbum("Alice-Family-Album");
-            assertTrue(this.clientPage.wasDenied());
-
-            loginToClientPage("alice", "alice");
-            this.clientPage.accountRevokeResource("Alice-Family-Album", "jdoe");
-
-            loginToClientPage("jdoe", "jdoe");
-            this.clientPage.viewAllAlbums();
-            this.clientPage.viewAlbum("Alice-Family-Album");
-            assertTrue(this.clientPage.wasDenied());
-        } finally {
-            this.deployer.undeploy(RESOURCE_SERVER_ID);
-        }
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice-Family-Album", true);
+        clientPage.accountShareResource("Alice-Family-Album", "jdoe");
+
+        loginToClientPage("jdoe", "jdoe");
+        clientPage.viewAllAlbums();
+        clientPage.viewAlbum("Alice-Family-Album", false);
+        clientPage.navigateTo();
+        clientPage.viewAllAlbums();
+        clientPage.deleteAlbum("Alice-Family-Album", false);
+
+        loginToClientPage("alice", "alice");
+        clientPage.createAlbum("Alice-Family-Album", true);
+        clientPage.accountShareRemoveScope("Alice-Family-Album", "jdoe", "album:delete");
+
+        loginToClientPage("jdoe", "jdoe");
+        clientPage.viewAllAlbums();
+        clientPage.viewAlbum("Alice-Family-Album", false);
+        clientPage.navigateTo();
+        clientPage.viewAllAlbums();
+        clientPage.deleteAlbum("Alice-Family-Album", true);
+
+        loginToClientPage("alice", "alice");
+        clientPage.accountRevokeResource("Alice-Family-Album", "jdoe");
+
+        loginToClientPage("jdoe", "jdoe");
+        clientPage.viewAllAlbums();
+        clientPage.viewAlbum("Alice-Family-Album", true);
     }
 
     private void importResourceServerSettings() throws FileNotFoundException {
@@ -791,6 +685,7 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
     }
 
     private void loginToClientPage(String username, String password, String... scopes) throws InterruptedException {
+        log.debugf("--logging in as {0} with password: {1}; scopes: {2}", username, password, Arrays.toString(scopes));
         // We need to log out by deleting cookies because the log out button sometimes doesn't work in PhantomJS
         deleteAllCookiesForTestRealm();
         clientPage.navigateTo();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java
index 2661185..5c6b0eb 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java
@@ -379,6 +379,32 @@ public abstract class AbstractServletPolicyEnforcerTest extends AbstractExampleA
         });
     }
 
+    @Test
+    public void testPathOrderWithAllPaths() {
+        performTests(() -> {
+            login("alice", "alice");
+            navigateTo("/keycloak-6623");
+            assertFalse(wasDenied());
+            navigateTo("/keycloak-6623/sub-resource");
+            assertFalse(wasDenied());
+
+            updatePermissionPolicies("Pattern 13 Permission", "Deny Policy");
+
+            login("alice", "alice");
+            navigateTo("/keycloak-6623");
+            assertTrue(wasDenied());
+            navigateTo("/keycloak-6623/sub-resource");
+            assertFalse(wasDenied());
+
+            updatePermissionPolicies("Pattern 14 Permission", "Deny Policy");
+
+            login("alice", "alice");
+            navigateTo("/keycloak-6623");
+            assertTrue(wasDenied());
+            navigateTo("/keycloak-6623/sub-resource/resource");
+            assertTrue(wasDenied());
+        });
+    }
 
     private void navigateTo(String path) {
         this.driver.navigate().to(getResourceServerUrl() + path);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
index 70ef820..9d3b5ec 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
@@ -81,4 +81,11 @@ public abstract class AbstractSAMLFilterServletAdapterTest extends AbstractSAMLS
     public void testErrorHandlingUnsigned() {
 
     }
+
+    @Test
+    @Override
+    @Ignore
+    public void testErrorHandlingSigned() {
+
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
index 7d0d43e..1459cf4 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
@@ -109,6 +109,8 @@ import static org.keycloak.testsuite.AbstractAuthTest.createUserRepresentation;
 import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
 import static org.keycloak.testsuite.admin.Users.setPasswordFor;
 import static org.keycloak.testsuite.auth.page.AuthRealm.SAMLSERVLETDEMO;
+import static org.keycloak.testsuite.saml.AbstractSamlTest.REALM_PRIVATE_KEY;
+import static org.keycloak.testsuite.saml.AbstractSamlTest.REALM_PUBLIC_KEY;
 import static org.keycloak.testsuite.util.IOUtil.loadRealm;
 import static org.keycloak.testsuite.util.IOUtil.loadXML;
 import static org.keycloak.testsuite.util.IOUtil.modifyDocElementAttribute;
@@ -978,22 +980,30 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
 
     @Test
     public void testErrorHandlingUnsigned() throws Exception {
-        Client client = ClientBuilder.newClient();
-        // make sure
-        Response response = client.target(employeeServletPage.toString()).request().get();
-        response.close();
         SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
-                .destination(employeeServletPage.toString() + "/saml")
+                .destination(employeeSigServletPage.toString() + "/saml")
                 .issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
                 .status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
-        BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder()
-                .relayState(null);
         Document document = builder.buildDocument();
-        URI uri = binding.redirectBinding(document).generateURI(employeeServletPage.toString() + "/saml", false);
-        response = client.target(uri).request().get();
-        String errorPage = response.readEntity(String.class);
-        response.close();
-        Assert.assertEquals(403, response.getStatus());
+
+        new SamlClientBuilder()
+                .addStep((client, currentURI, currentResponse, context) ->
+                        Binding.REDIRECT.createSamlUnsignedResponse(URI.create(employeeSigServletPage.toString() + "/saml"), null, document))
+                .execute(closeableHttpResponse -> assertThat(closeableHttpResponse, bodyHC(containsString("INVALID_SIGNATURE"))));
+    }
+
+    @Test
+    public void testErrorHandlingSigned() throws Exception {
+        SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
+                .destination(employeeSigServletPage.toString() + "/saml")
+                .issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
+                .status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
+        Document document = builder.buildDocument();
+
+        new SamlClientBuilder()
+                .addStep((client, currentURI, currentResponse, context) ->
+                        Binding.REDIRECT.createSamlSignedResponse(URI.create(employeeSigServletPage.toString() + "/saml"), null, document, REALM_PRIVATE_KEY, REALM_PUBLIC_KEY))
+                .execute(closeableHttpResponse -> assertThat(closeableHttpResponse, bodyHC(containsString("ERROR_STATUS"))));
     }
 
     @Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
index 51a2cae..8546c2a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
@@ -18,22 +18,26 @@
 package org.keycloak.testsuite.admin.client.authorization;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.BeforeClass;
 import org.keycloak.admin.client.resource.AuthorizationResource;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.ResourceScopeResource;
 import org.keycloak.admin.client.resource.ResourceScopesResource;
 import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
 import org.keycloak.testsuite.ProfileAssume;
 import org.keycloak.testsuite.admin.client.AbstractClientTest;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
 
 import javax.ws.rs.core.Response;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+
+import java.util.List;
 
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@@ -42,24 +46,32 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
 
     protected static final String RESOURCE_SERVER_CLIENT_ID = "resource-server-test";
 
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm("authz-test");
+    }
+
+    @Override
+    protected String getRealmId() {
+        return "authz-test";
+    }
+
     @BeforeClass
     public static void enabled() {
         ProfileAssume.assumePreview();
     }
 
-    @Before
-    public void onBeforeAuthzTests() {
-        createOidcClient(RESOURCE_SERVER_CLIENT_ID);
-
-        ClientRepresentation resourceServer = getResourceServer();
-
-        assertEquals(RESOURCE_SERVER_CLIENT_ID, resourceServer.getName());
-        assertFalse(resourceServer.getAuthorizationServicesEnabled());
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        testRealms.add(createTestRealm().build());
+        super.addTestRealms(testRealms);
     }
 
     @After
-    public void onAfterAuthzTests() {
-        getClientResource().remove();
+    public void onAfterReenableAuthorization() {
+        enableAuthorizationServices(false);
+        enableAuthorizationServices(true);
     }
 
     protected ClientResource getClientResource() {
@@ -70,22 +82,22 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
         return findClientRepresentation(RESOURCE_SERVER_CLIENT_ID);
     }
 
-    protected void enableAuthorizationServices() {
+    protected void enableAuthorizationServices(boolean enable) {
         ClientRepresentation resourceServer = getResourceServer();
 
-        resourceServer.setAuthorizationServicesEnabled(true);
+        resourceServer.setAuthorizationServicesEnabled(enable);
         resourceServer.setServiceAccountsEnabled(true);
         resourceServer.setPublicClient(false);
         resourceServer.setSecret("secret");
 
         getClientResource().update(resourceServer);
 
-        AuthorizationResource authorization = getClientResource().authorization();
-        ResourceServerRepresentation settings = authorization.exportSettings();
-
-        settings.setAllowRemoteResourceManagement(true);
-
-        authorization.update(settings);
+        if (enable) {
+            AuthorizationResource authorization = getClientResource().authorization();
+            ResourceServerRepresentation settings = authorization.exportSettings();
+            settings.setAllowRemoteResourceManagement(true);
+            authorization.update(settings);
+        }
     }
 
     protected ResourceScopeResource createDefaultScope() {
@@ -108,4 +120,17 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
 
         return resources.scope(stored.getId());
     }
+
+    private RealmBuilder createTestRealm() {
+        return RealmBuilder.create().name("authz-test")
+                .user(UserBuilder.create().username("marta").password("password"))
+                .user(UserBuilder.create().username("kolo").password("password"))
+                .client(ClientBuilder.create().clientId(RESOURCE_SERVER_CLIENT_ID)
+                        .name(RESOURCE_SERVER_CLIENT_ID)
+                        .secret("secret")
+                        .authorizationServicesEnabled(true)
+                        .redirectUris("http://localhost/" + RESOURCE_SERVER_CLIENT_ID)
+                        .defaultRoles("uma_protection")
+                        .directAccessGrants());
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java
index 2d549de..f642979 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java
@@ -24,6 +24,7 @@ import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
 import org.keycloak.representations.idm.authorization.PolicyRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
@@ -44,17 +45,38 @@ public class AuthorizationTest extends AbstractAuthorizationTest {
         ClientResource clientResource = getClientResource();
         ClientRepresentation resourceServer = getResourceServer();
 
-        enableAuthorizationServices();
+        enableAuthorizationServices(false);
+        enableAuthorizationServices(true);
+
+        clientResource.authorization().resources().create(new ResourceRepresentation("Should be removed"));
+
+        JSPolicyRepresentation policy = new JSPolicyRepresentation();
+
+        policy.setName("should be removed");
+        policy.setCode("");
+
+        clientResource.authorization().policies().js().create(policy);
+
+        List<ResourceRepresentation> defaultResources = clientResource.authorization().resources().resources();
+
+        assertEquals(2, defaultResources.size());
+
+        List<PolicyRepresentation> defaultPolicies = clientResource.authorization().policies().policies();
+
+        assertEquals(3, defaultPolicies.size());
+
+        enableAuthorizationServices(false);
+        enableAuthorizationServices(true);
 
         ResourceServerRepresentation settings = clientResource.authorization().getSettings();
 
         assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
         assertEquals(resourceServer.getId(), settings.getClientId());
-        List<ResourceRepresentation> defaultResources = clientResource.authorization().resources().resources();
+        defaultResources = clientResource.authorization().resources().resources();
 
         assertEquals(1, defaultResources.size());
 
-        List<PolicyRepresentation> defaultPolicies = clientResource.authorization().policies().policies();
+        defaultPolicies = clientResource.authorization().policies().policies();
 
         assertEquals(2, defaultPolicies.size());
     }
@@ -72,8 +94,6 @@ public class AuthorizationTest extends AbstractAuthorizationTest {
         ClientResource clientResource = getClientResource();
         ClientRepresentation resourceServer = getResourceServer();
 
-        enableAuthorizationServices();
-
         ResourceServerRepresentation settings = clientResource.authorization().getSettings();
 
         assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java
index c71d12f..59d655a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java
@@ -46,8 +46,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
         String permissionName = "resource-based-permission";
         
         ClientResource clientResource = getClientResource();
-
-        enableAuthorizationServices();
         AuthorizationResource authorizationResource = clientResource.authorization();
 
         //get Default Resource
@@ -89,8 +87,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
     @Test
     public void testRoleBasedPolicy() {
         ClientResource clientResource = getClientResource();
-
-        enableAuthorizationServices();
         AuthorizationResource authorizationResource = clientResource.authorization();
         
         ClientRepresentation account = testRealmResource().clients().findByClientId("account").get(0);
@@ -121,8 +117,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
     @Test
     public void testRoleBasedPolicyWithMultipleRoles() {
         ClientResource clientResource = getClientResource();
-
-        enableAuthorizationServices();
         AuthorizationResource authorizationResource = clientResource.authorization();
         
         testRealmResource().clients().create(ClientBuilder.create().clientId("test-client-1").defaultRoles("client-role").build()).close();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java
index bd4d973..322492d 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java
@@ -54,19 +54,6 @@ public class GenericPolicyManagementTest extends AbstractAuthorizationTest {
 
     private static final String[] EXPECTED_BUILTIN_POLICY_PROVIDERS = {"test", "user", "role", "rules", "js", "time", "aggregate", "scope", "resource"};
 
-    @Before
-    @Override
-    public void onBeforeAuthzTests() {
-        super.onBeforeAuthzTests();
-        enableAuthorizationServices();
-    }
-
-    @After
-    @Override
-    public void onAfterAuthzTests() {
-        super.onAfterAuthzTests();
-    }
-
     @Test
     public void testCreate() {
         PolicyRepresentation newPolicy = createTestingPolicy().toRepresentation();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java
index a308ec0..0524111 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java
@@ -48,24 +48,9 @@ public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
         testRealmResource().users().create(UserBuilder.create().username("alice").build());
     }
 
-    @After
-    public void onAfterAuthzTests() {
-        ClientResource clientResource = getClientResource();
-
-        // Needed to disable authz first. TODO: Looks like a bug. Check later...
-        ClientRepresentation client = clientResource.toRepresentation();
-        client.setAuthorizationServicesEnabled(false);
-        clientResource.update(client);
-
-        getClientResource().remove();
-    }
-
     @Test
     public void testImportUnorderedSettings() throws Exception {
         ClientResource clientResource = getClientResource();
-
-        enableAuthorizationServices();
-
         ResourceServerRepresentation toImport = JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/import-authorization-unordered-settings.json"), ResourceServerRepresentation.class);
 
         realmsResouce().realm(getRealmId()).roles().create(new RoleRepresentation("user", null, false));
@@ -75,6 +60,6 @@ public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
 
         authorizationResource.importSettings(toImport);
 
-        assertEquals(15, authorizationResource.policies().policies().size());
+        assertEquals(13, authorizationResource.policies().policies().size());
     }
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java
index 3c1a2f1..41fcb66 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java
@@ -18,12 +18,11 @@
 
 package org.keycloak.testsuite.admin.client.authorization;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.ResourceResource;
 import org.keycloak.admin.client.resource.ResourcesResource;
 import org.keycloak.authorization.client.util.HttpResponseException;
-import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceRepresentation;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
 
@@ -35,6 +34,7 @@ import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -45,33 +45,6 @@ import static org.junit.Assert.fail;
  */
 public class ResourceManagementTest extends AbstractAuthorizationTest {
 
-    @Before
-    @Override
-    public void onBeforeAuthzTests() {
-        super.onBeforeAuthzTests();
-        enableAuthorizationServices();
-    }
-
-    @Override
-    public void addTestRealms(List<RealmRepresentation> testRealms) {
-        RealmRepresentation testRealmRep = new RealmRepresentation();
-        testRealmRep.setId("authz-test");
-        testRealmRep.setRealm("authz-test");
-        testRealmRep.setEnabled(true);
-        testRealms.add(testRealmRep);
-    }
-
-    @Override
-    public void setDefaultPageUriParameters() {
-        super.setDefaultPageUriParameters();
-        testRealmPage.setAuthRealm("authz-test");
-    }
-
-    @Override
-    protected String getRealmId() {
-        return "authz-test";
-    }
-
     @Test
     public void testCreate() {
         ResourceRepresentation newResource = createResource();
@@ -103,6 +76,28 @@ public class ResourceManagementTest extends AbstractAuthorizationTest {
     }
 
     @Test
+    public void failCreateWithSameNameDifferentOwner() {
+        ResourceRepresentation martaResource = createResource("Resource A", "marta", null, null, null);
+        ResourceRepresentation koloResource = createResource("Resource A", "kolo", null, null, null);
+
+        assertNotNull(martaResource.getId());
+        assertNotNull(koloResource.getId());
+        assertNotEquals(martaResource.getId(), koloResource.getId());
+
+        assertEquals(2, getClientResource().authorization().resources().findByName(martaResource.getName()).size());
+
+        List<ResourceRepresentation> martaResources = getClientResource().authorization().resources().findByName(martaResource.getName(), "marta");
+
+        assertEquals(1, martaResources.size());
+        assertEquals(martaResource.getId(), martaResources.get(0).getId());
+
+        List<ResourceRepresentation> koloResources = getClientResource().authorization().resources().findByName(martaResource.getName(), "kolo");
+
+        assertEquals(1, koloResources.size());
+        assertEquals(koloResource.getId(), koloResources.get(0).getId());
+    }
+
+    @Test
     public void testUpdate() {
         ResourceRepresentation resource = createResource();
 
@@ -198,12 +193,17 @@ public class ResourceManagementTest extends AbstractAuthorizationTest {
     }
 
     private ResourceRepresentation createResource() {
+        return createResource("Test Resource", null, "/test/*", "test-resource", "icon-test-resource");
+    }
+
+    private ResourceRepresentation createResource(String name, String owner, String uri, String type, String iconUri) {
         ResourceRepresentation newResource = new ResourceRepresentation();
 
-        newResource.setName("Test Resource");
-        newResource.setUri("/test/*");
-        newResource.setType("test-resource");
-        newResource.setIconUri("icon-test-resource");
+        newResource.setName(name);
+        newResource.setUri(uri);
+        newResource.setType(type);
+        newResource.setIconUri(iconUri);
+        newResource.setOwner(owner != null ? new ResourceOwnerRepresentation(owner) : null);
 
         return doCreateResource(newResource);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java
index 53c68ed..a784566 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java
@@ -95,7 +95,7 @@ public class RulesPolicyManagementTest extends AbstractPolicyManagementTest {
         representation.setDescription("description");
         representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
         representation.setLogic(Logic.NEGATIVE);
-        representation.setArtifactGroupId("org.keycloak");
+        representation.setArtifactGroupId("org.keycloak.testsuite");
         representation.setArtifactId("photoz-authz-policy");
         representation.setArtifactVersion(System.getProperty("project.version"));
         representation.setModuleName("PhotozAuthzOwnerPolicy");
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java
index bcb8b1b..9590078 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java
@@ -33,13 +33,6 @@ import static org.junit.Assert.assertEquals;
  */
 public class ScopeManagementTest extends AbstractAuthorizationTest {
 
-    @Before
-    @Override
-    public void onBeforeAuthzTests() {
-        super.onBeforeAuthzTests();
-        enableAuthorizationServices();
-    }
-
     @Test
     public void testCreate() {
         ScopeRepresentation newScope = createDefaultScope().toRepresentation();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java
index 37dd1ff..fc9ccdd 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java
@@ -191,7 +191,7 @@ public class AuthorizationAPITest extends AbstractAuthzTest {
         assertEquals(resourceServerClientId, rpt.getAudience()[0]);
     }
 
-    private RealmResource getRealm() throws Exception {
+    private RealmResource getRealm() {
         return adminClient.realm("authz-test");
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationTest.java
new file mode 100644
index 0000000..16eb0cb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationTest.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.authz;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import javax.ws.rs.core.Response;
+
+import org.jetbrains.annotations.NotNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.AuthorizationResource;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.ResourcesResource;
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.Configuration;
+import org.keycloak.jose.jws.JWSInputException;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.AccessToken.Authorization;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.AuthorizationRequest;
+import org.keycloak.representations.idm.authorization.AuthorizationResponse;
+import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
+import org.keycloak.representations.idm.authorization.Permission;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
+import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.RoleBuilder;
+import org.keycloak.testsuite.util.RolesBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationTest extends AbstractAuthzTest {
+
+    private AuthzClient authzClient;
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        testRealms.add(RealmBuilder.create().name("authz-test")
+                .roles(RolesBuilder.create().realmRole(RoleBuilder.create().name("uma_authorization").build()))
+                .user(UserBuilder.create().username("marta").password("password").addRoles("uma_authorization"))
+                .user(UserBuilder.create().username("kolo").password("password"))
+                .client(ClientBuilder.create().clientId("resource-server-test")
+                    .secret("secret")
+                    .authorizationServicesEnabled(true)
+                    .redirectUris("http://localhost/resource-server-test")
+                    .defaultRoles("uma_protection")
+                    .directAccessGrants())
+                .client(ClientBuilder.create().clientId("test-client")
+                    .secret("secret")
+                    .authorizationServicesEnabled(true)
+                    .redirectUris("http://localhost/test-client")
+                    .directAccessGrants())
+                .build());
+    }
+
+    @Before
+    public void configureAuthorization() throws Exception {
+        ClientResource client = getClient();
+        AuthorizationResource authorization = client.authorization();
+
+        JSPolicyRepresentation policy = new JSPolicyRepresentation();
+
+        policy.setName("Grant Policy");
+        policy.setCode("$evaluation.grant();");
+
+        authorization.policies().js().create(policy).close();
+
+        policy = new JSPolicyRepresentation();
+
+        policy.setName("Deny Policy");
+        policy.setCode("$evaluation.deny();");
+    }
+
+    @After
+    public void onAfter() {
+        ResourcesResource resources = getClient().authorization().resources();
+        List<ResourceRepresentation> existingResources = resources.resources();
+
+        for (ResourceRepresentation resource : existingResources) {
+            resources.resource(resource.getId()).remove();
+        }
+    }
+
+    @Test
+    public void testResourceWithSameNameDifferentOwner() throws JWSInputException {
+        ResourceRepresentation koloResource = createResource("Resource A", "kolo", "Scope A", "Scope B");
+
+        createResourcePermission(koloResource, "Grant Policy");
+
+        ResourceRepresentation martaResource = createResource("Resource A", "marta", "Scope A", "Scope B");
+
+        createResourcePermission(martaResource, "Grant Policy");
+
+        assertNotEquals(koloResource.getId(), martaResource.getId());
+
+        AuthorizationRequest request = new AuthorizationRequest();
+
+        request.addPermission("Resource A");
+
+        List<Permission> permissions = authorize("kolo", "password", request);
+
+        assertEquals(1, permissions.size());
+
+        Permission permission = permissions.get(0);
+        assertTrue(permission.getScopes().containsAll(Arrays.asList("Scope A", "Scope B")));
+
+        assertEquals(koloResource.getId(), permission.getResourceId());
+
+        permissions = authorize("marta", "password", request);
+
+        assertEquals(1, permissions.size());
+
+        permission = permissions.get(0);
+
+        assertEquals(martaResource.getId(), permission.getResourceId());
+        assertTrue(permission.getScopes().containsAll(Arrays.asList("Scope A", "Scope B")));
+    }
+
+    @Test
+    public void testResourceServerWithSameNameDifferentOwner() {
+        ResourceRepresentation koloResource = createResource("Resource A", "kolo", "Scope A", "Scope B");
+
+        createResourcePermission(koloResource, "Grant Policy");
+
+        ResourceRepresentation serverResource = createResource("Resource A", null, "Scope A", "Scope B");
+
+        createResourcePermission(serverResource, "Grant Policy");
+
+        AuthorizationRequest request = new AuthorizationRequest();
+
+        request.addPermission("Resource A");
+
+        List<Permission> permissions = authorize("kolo", "password", request);
+
+        assertEquals(2, permissions.size());
+
+        for (Permission permission : permissions) {
+            assertTrue(permission.getResourceId().equals(koloResource.getId()) || permission.getResourceId().equals(serverResource.getId()));
+            assertEquals("Resource A", permission.getResourceName());
+        }
+    }
+
+    private List<Permission> authorize(String userName, String password, AuthorizationRequest request) {
+        AuthorizationResponse response = getAuthzClient().authorization(userName, password).authorize(request);
+        AccessToken token = toAccessToken(response.getToken());
+        Authorization authorization = token.getAuthorization();
+        return authorization.getPermissions();
+    }
+
+    private void createResourcePermission(ResourceRepresentation resource, String... policies) {
+        ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
+
+        permission.setName(resource.getName() + UUID.randomUUID().toString());
+        permission.addResource(resource.getId());
+        permission.addPolicy(policies);
+
+        Response response = getClient().authorization().permissions().resource().create(permission);
+
+        assertEquals(201, response.getStatus());
+    }
+
+    @NotNull
+    private ResourceRepresentation createResource(String name, String owner, String... scopes) {
+        ResourceRepresentation resource = new ResourceRepresentation();
+
+        resource.setName(name);
+        resource.setOwner(owner != null ? new ResourceOwnerRepresentation(owner) : null);
+        resource.addScope(scopes);
+
+        Response response = getClient().authorization().resources().create(resource);
+        ResourceRepresentation stored = response.readEntity(ResourceRepresentation.class);
+        response.close();
+
+        resource.setId(stored.getId());
+
+        return resource;
+    }
+
+    private RealmResource getRealm() {
+        return adminClient.realm("authz-test");
+    }
+
+    private ClientResource getClient() {
+        ClientsResource clients = getRealm().clients();
+        return clients.findByClientId("resource-server-test").stream().map(representation -> clients.get(representation.getId())).findFirst().orElseThrow(() -> new RuntimeException("Expected client [resource-server-test]"));
+    }
+
+    private AuthzClient getAuthzClient() {
+        if (authzClient == null) {
+            try {
+                authzClient = AuthzClient.create(JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/default-keycloak.json"), Configuration.class));
+            } catch (IOException cause) {
+                throw new RuntimeException("Failed to create authz client", cause);
+            }
+        }
+
+        return authzClient;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java
index 21bb9ee..f488d32 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java
@@ -52,7 +52,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
     public void testCreatePermissionTicketWithResourceName() throws Exception {
         ResourceRepresentation resource = addResource("Resource A", "kolo", true);
         AuthzClient authzClient = getAuthzClient();
-        PermissionResponse response = authzClient.protection("marta", "password").permission().create(new PermissionRequest(resource.getName()));
+        PermissionResponse response = authzClient.protection("marta", "password").permission().create(new PermissionRequest(resource.getId()));
         AuthorizationRequest request = new AuthorizationRequest();
         request.setTicket(response.getTicket());
         request.setClaimToken(authzClient.obtainAccessToken("marta", "password").getToken());
@@ -125,7 +125,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
     @Test
     public void testDeleteScopeAndPermissionTicket() throws Exception {
         ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB", "ScopeC");
-        PermissionRequest permissionRequest = new PermissionRequest(resource.getName());
+        PermissionRequest permissionRequest = new PermissionRequest(resource.getId());
 
         permissionRequest.setScopes(new HashSet<>(Arrays.asList("ScopeA", "ScopeB", "ScopeC")));
 
@@ -164,7 +164,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
     @Test
     public void testRemoveScopeFromResource() throws Exception {
         ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB");
-        PermissionRequest permissionRequest = new PermissionRequest(resource.getName(), "ScopeA", "ScopeB");
+        PermissionRequest permissionRequest = new PermissionRequest(resource.getId(), "ScopeA", "ScopeB");
         AuthzClient authzClient = getAuthzClient();
         PermissionResponse response = authzClient.protection("marta", "password").permission().create(permissionRequest);
 
@@ -255,7 +255,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
 
         getClient(getRealm()).authorization().resources().resource(resourceA.getId()).update(resourceA);
 
-        PermissionRequest permissionRequest = new PermissionRequest("Resource A");
+        PermissionRequest permissionRequest = new PermissionRequest(resourceA.getId());
 
         permissionRequest.setScopes(new HashSet<>(Arrays.asList("ScopeA", "ScopeC")));
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationTest.java
new file mode 100644
index 0000000..9ffad7b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationTest.java
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.authz;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.Decision.Effect;
+import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.common.DefaultEvaluationContext;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.DefaultEvaluation;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.GroupMembershipMapper;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
+import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.GroupBuilder;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.RoleBuilder;
+import org.keycloak.testsuite.util.RolesBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyEvaluationTest extends AbstractAuthzTest {
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        ProtocolMapperRepresentation groupProtocolMapper = new ProtocolMapperRepresentation();
+
+        groupProtocolMapper.setName("groups");
+        groupProtocolMapper.setProtocolMapper(GroupMembershipMapper.PROVIDER_ID);
+        groupProtocolMapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+        groupProtocolMapper.setConsentRequired(false);
+        Map<String, String> config = new HashMap<>();
+        config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "groups");
+        config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
+        config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
+        config.put("full.path", "true");
+        groupProtocolMapper.setConfig(config);
+
+        testRealms.add(RealmBuilder.create().name("authz-test")
+                .roles(RolesBuilder.create()
+                        .realmRole(RoleBuilder.create().name("uma_authorization").build())
+                        .realmRole(RoleBuilder.create().name("role-a").build())
+                        .realmRole(RoleBuilder.create().name("role-b").build())
+                )
+                .group(GroupBuilder.create().name("Group A")
+                        .subGroups(Arrays.asList("Group B", "Group D").stream().map(name -> {
+                            if ("Group B".equals(name)) {
+                                return GroupBuilder.create().name(name).subGroups(Arrays.asList("Group C", "Group E").stream().map(new Function<String, GroupRepresentation>() {
+                                    @Override
+                                    public GroupRepresentation apply(String name) {
+                                        return GroupBuilder.create().name(name).build();
+                                    }
+                                }).collect(Collectors.toList())).build();
+                            }
+                            return GroupBuilder.create().name(name).realmRoles(Arrays.asList("role-a")).build();
+                        }).collect(Collectors.toList())).build())
+                .group(GroupBuilder.create().name("Group E").build())
+                .user(UserBuilder.create().username("marta").password("password").addRoles("uma_authorization", "role-a").addGroups("Group A"))
+                .user(UserBuilder.create().username("alice").password("password").addRoles("uma_authorization").addGroups("/Group A/Group B/Group E"))
+                .user(UserBuilder.create().username("kolo").password("password").addRoles("uma_authorization").addGroups("/Group A/Group D"))
+                .user(UserBuilder.create().username("trinity").password("password").addRoles("uma_authorization").role("role-mapping-client", "client-role-a"))
+                .user(UserBuilder.create().username("jdoe").password("password").addGroups("/Group A/Group B", "/Group A/Group D"))
+                .client(ClientBuilder.create().clientId("resource-server-test")
+                        .secret("secret")
+                        .authorizationServicesEnabled(true)
+                        .redirectUris("http://localhost/resource-server-test")
+                        .defaultRoles("uma_protection")
+                        .directAccessGrants()
+                        .protocolMapper(groupProtocolMapper))
+                .client(ClientBuilder.create().clientId("role-mapping-client")
+                        .defaultRoles("client-role-a", "client-role-b"))
+                .build());
+    }
+
+    @Deployment
+    public static WebArchive deploy() {
+        return RunOnServerDeployment.create(AbstractAuthzTest.class);
+    }
+
+    @Test
+    public void testCheckUserInGroup() {
+        testingClient.server().run(PolicyEvaluationTest::testCheckUserInGroup);
+    }
+
+    public static void testCheckUserInGroup(KeycloakSession session) {
+        session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+        AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+        ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+        JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+        policyRepresentation.setName("testCheckUserInGroup");
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInGroup('marta', 'Group C')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+        PolicyProvider provider = authorization.getProvider(policy.getType());
+
+        DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertNull(evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInGroup('marta', 'Group A')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInGroup('marta', '/Group A')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInGroup('marta', '/Group A/Group B')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertNull(evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInGroup('alice', '/Group A/Group B/Group E')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInGroup('alice', '/Group A')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (!realm.isUserInGroup('alice', '/Group A', false)) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertNull(evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInGroup('alice', '/Group E')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertNull(evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInGroup('alice', 'Group E')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertNull(evaluation.getEffect());
+    }
+
+    @Test
+    public void testCheckUserInRole() {
+        testingClient.server().run(PolicyEvaluationTest::testCheckUserInRole);
+    }
+
+    public static void testCheckUserInRole(KeycloakSession session) {
+        session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+        AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+        ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+        JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+        policyRepresentation.setName("testCheckUserInRole");
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInRealmRole('marta', 'role-a')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+        PolicyProvider provider = authorization.getProvider(policy.getType());
+
+        DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInRealmRole('marta', 'role-b')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertNull(evaluation.getEffect());
+    }
+
+    @Test
+    public void testCheckUserInClientRole() {
+        testingClient.server().run(PolicyEvaluationTest::testCheckUserInClientRole);
+    }
+
+    public static void testCheckUserInClientRole(KeycloakSession session) {
+        session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+        AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+        ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+        JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+        policyRepresentation.setName("testCheckUserInClientRole");
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInClientRole('trinity', 'role-mapping-client', 'client-role-a')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+        PolicyProvider provider = authorization.getProvider(policy.getType());
+
+        DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isUserInRealmRole('trinity', 'client-role-b')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertNull(evaluation.getEffect());
+    }
+
+    @Test
+    public void testCheckGroupInRole() {
+        testingClient.server().run(PolicyEvaluationTest::testCheckGroupInRole);
+    }
+
+    public static void testCheckGroupInRole(KeycloakSession session) {
+        session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+        AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+        ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+        JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+        policyRepresentation.setName("testCheckGroupInRole");
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isGroupInRole('/Group A/Group D', 'role-a')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+        PolicyProvider provider = authorization.getProvider(policy.getType());
+
+        DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+        builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("if (realm.isGroupInRole('/Group A/Group D', 'role-b')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        policyRepresentation.setId(policy.getId());
+        policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+        evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertNull(evaluation.getEffect());
+    }
+
+    @Test
+    public void testCheckUserRealmRoles() {
+        testingClient.server().run(PolicyEvaluationTest::testCheckUserRealmRoles);
+    }
+
+    public static void testCheckUserRealmRoles(KeycloakSession session) {
+        session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+        AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+        ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+        JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+        policyRepresentation.setName("testCheckUserRealmRoles");
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("var roles = realm.getUserRealmRoles('marta');");
+        builder.append("if (roles.size() == 2 && roles.contains('uma_authorization') && roles.contains('role-a')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+        PolicyProvider provider = authorization.getProvider(policy.getType());
+
+        DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+    }
+
+    @Test
+    public void testCheckUserClientRoles() {
+        testingClient.server().run(PolicyEvaluationTest::testCheckUserClientRoles);
+    }
+
+    public static void testCheckUserClientRoles(KeycloakSession session) {
+        session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+        AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+        ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+        JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+        policyRepresentation.setName("testCheckUserClientRoles");
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("var roles = realm.getUserClientRoles('trinity', 'role-mapping-client');");
+        builder.append("if (roles.size() == 1 && roles.contains('client-role-a')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+        PolicyProvider provider = authorization.getProvider(policy.getType());
+
+        DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+    }
+
+    @Test
+    public void testCheckUserGroups() {
+        testingClient.server().run(PolicyEvaluationTest::testCheckUserGroups);
+    }
+
+    public static void testCheckUserGroups(KeycloakSession session) {
+        session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+        AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+        ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+        JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+        policyRepresentation.setName("testCheckUserGroups");
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("var groups = realm.getUserGroups('jdoe');");
+        builder.append("if (groups.size() == 2 && groups.contains('/Group A/Group B') && groups.contains('/Group A/Group D')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+        PolicyProvider provider = authorization.getProvider(policy.getType());
+
+        DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+    }
+
+    @Test
+    public void testCheckUserAttributes() {
+        testingClient.server().run(PolicyEvaluationTest::testCheckUserAttributes);
+    }
+
+    public static void testCheckUserAttributes(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName("authz-test");
+        UserModel jdoe = session.users().getUserByUsername("jdoe", realm);
+
+        jdoe.setAttribute("a1", Arrays.asList("1", "2"));
+        jdoe.setSingleAttribute("a2", "3");
+
+        session.getContext().setRealm(realm);
+        AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+        ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+        JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+        policyRepresentation.setName("testCheckUserAttributes");
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("var realm = $evaluation.getRealm();");
+        builder.append("var attributes = realm.getUserAttributes('jdoe');");
+        builder.append("if (attributes.size() == 2 && attributes.containsKey('a1') && attributes.containsKey('a2') && attributes.get('a1').size() == 2 && attributes.get('a2').get(0).equals('3')) { $evaluation.grant(); }");
+
+        policyRepresentation.setCode(builder.toString());
+
+        Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+        PolicyProvider provider = authorization.getProvider(policy.getType());
+
+        DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+        provider.evaluate(evaluation);
+
+        Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+    }
+
+    @NotNull
+    private static DefaultEvaluation createEvaluation(KeycloakSession session, AuthorizationProvider authorization, ResourceServer resourceServer, Policy policy) {
+        return new DefaultEvaluation(new ResourcePermission(null, null, resourceServer), new DefaultEvaluationContext(new Identity() {
+            @Override
+            public String getId() {
+                return null;
+            }
+
+            @Override
+            public Attributes getAttributes() {
+                return null;
+            }
+        }, session), policy, policy, new Decision() {
+            @Override
+            public void onDecision(Evaluation evaluation) {
+
+            }
+        }, authorization);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java
index 41448cf..5d4c1a1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java
@@ -123,7 +123,7 @@ public class UmaGrantTypeTest extends AbstractResourceServerTest {
         ResourceRepresentation resourceA = addResource("Resource Marta", "marta", true, "ScopeA", "ScopeB", "ScopeC");
 
         permission.setName(resourceA.getName() + " Permission");
-        permission.addResource(resourceA.getName());
+        permission.addResource(resourceA.getId());
         permission.addPolicy("Default Policy");
 
         getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -131,7 +131,7 @@ public class UmaGrantTypeTest extends AbstractResourceServerTest {
         ResourceRepresentation resourceB = addResource("Resource B", "marta", "ScopeA", "ScopeB", "ScopeC");
 
         permission.setName(resourceB.getName() + " Permission");
-        permission.addResource(resourceB.getName());
+        permission.addResource(resourceB.getId());
         permission.addPolicy("Default Policy");
 
         getClient(getRealm()).authorization().permissions().resource().create(permission).close();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java
index f8dd3de..5ef774e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java
@@ -68,7 +68,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
 
         permission.setName(resource.getName() + " Permission");
-        permission.addResource(resource.getName());
+        permission.addResource(resource.getId());
         permission.addPolicy("Only Owner Policy");
 
         getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -91,7 +91,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         assertTrue(permissions.isEmpty());
 
         try {
-            response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
+            response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
             fail("User should have access to resource from another user");
         } catch (AuthorizationDeniedException ade) {
 
@@ -104,7 +104,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
 
         permission.setName(resource.getName() + " Permission");
-        permission.addResource(resource.getName());
+        permission.addResource(resource.getId());
         permission.addPolicy("Only Owner Policy");
 
         getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -127,7 +127,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         assertTrue(permissions.isEmpty());
 
         try {
-            response = authorize("kolo", "password", "Resource A", new String[] {});
+            response = authorize("kolo", "password", resource.getId(), new String[] {});
             fail("User should have access to resource from another user");
         } catch (AuthorizationDeniedException ade) {
 
@@ -156,7 +156,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
             assertTrue(ticket.isGranted());
         }
 
-        response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
+        response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
         rpt = response.getToken();
 
         assertNotNull(rpt);
@@ -180,7 +180,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         resource = addResource("Resource A", "marta", true);
 
         permission.setName(resource.getName() + " Permission");
-        permission.addResource(resource.getName());
+        permission.addResource(resource.getId());
         permission.addPolicy("Only Owner Policy");
 
         getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -203,7 +203,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         assertTrue(permissions.isEmpty());
 
         try {
-            response = authorize("kolo", "password", "Resource A", new String[] {});
+            response = authorize("kolo", "password", resource.getId(), new String[] {});
             fail("User should have access to resource from another user");
         } catch (AuthorizationDeniedException ade) {
 
@@ -232,7 +232,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
             assertTrue(ticket.isGranted());
         }
 
-        response = authorize("kolo", "password", resource.getName(), new String[] {});
+        response = authorize("kolo", "password", resource.getId(), new String[] {});
         rpt = response.getToken();
 
         assertNotNull(rpt);
@@ -249,7 +249,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         assertPermissions(permissions, resource.getName());
         assertTrue(permissions.isEmpty());
 
-        response = authorize("kolo", "password", resource.getName(), new String[] {});
+        response = authorize("kolo", "password", resource.getId(), new String[] {});
         rpt = response.getToken();
 
         assertNotNull(rpt);
@@ -282,7 +282,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
 
         permission.setName(resource.getName() + " Permission");
-        permission.addResource(resource.getName());
+        permission.addResource(resource.getId());
         permission.addPolicy("Only Owner Policy");
 
         getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -305,7 +305,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         assertTrue(permissions.isEmpty());
 
         try {
-            response = authorize("kolo", "password", "Resource A", new String[] {"ScopeA"});
+            response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA"});
             fail("User should have access to resource from another user");
         } catch (AuthorizationDeniedException ade) {
 
@@ -324,7 +324,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
 
         permissionResource.update(ticket);
 
-        response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
+        response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
         rpt = response.getToken();
 
         assertNotNull(rpt);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java
index 0ae1117..0dad533 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java
@@ -377,10 +377,10 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest 
             File dir = new File(cleanServerBaseDir);
             if (dir.exists()) {
                 try {
-                    FileUtils.cleanDirectory(dir);
+                    dir.renameTo(new File(dir.getParentFile(), dir.getName() + "--" + System.currentTimeMillis()));
 
                     File deploymentsDir = new File(dir, "deployments");
-                    deploymentsDir.mkdir();
+                    FileUtils.forceMkdir(deploymentsDir);
                 } catch (IOException ioe) {
                     throw new RuntimeException("Failed to clean directory: " + cleanServerBaseDir, ioe);
                 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java
index cfd7907..3775e38 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java
@@ -30,6 +30,7 @@ import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.RefreshToken;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.util.ClientBuilder;
@@ -48,6 +49,7 @@ import static org.junit.Assert.assertEquals;
 public class ServiceAccountTest extends AbstractKeycloakTest {
 
     private static String userId;
+    private static String userName;
 
     @Rule
     public AssertEvents events = new AssertEvents(this);
@@ -89,10 +91,11 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
         realm.user(defaultUser);
 
         userId = KeycloakModelUtils.generateId();
+        userName = ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + enabledApp.getClientId();
 
         UserBuilder serviceAccountUser = UserBuilder.create()
                 .id(userId)
-                .username(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + enabledApp.getClientId())
+                .username(userName)
                 .serviceAccountId(enabledApp.getClientId());
         realm.user(serviceAccountUser);
 
@@ -116,7 +119,7 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
                 .session(accessToken.getSessionState())
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
-                .detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "service-account-cl")
+                .detail(Details.USERNAME, userName)
                 .assertEvent();
 
         assertEquals(accessToken.getSessionState(), refreshToken.getSessionState());
@@ -153,7 +156,7 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
                 .session(accessToken.getSessionState())
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
-                .detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "service-account-cl")
+                .detail(Details.USERNAME, userName)
                 .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
                 .assertEvent();
 
@@ -246,4 +249,24 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
         ClientManager.realm(adminClient.realm("test")).clientId("updated-client").renameTo("service-account-cl");
 
     }
+
+    @Test
+    public void refreshTokenRefreshForDisabledServiceAccount() throws Exception {
+        try {
+            oauth.clientId("service-account-cl");
+            OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest("secret1");
+            assertEquals(200, response.getStatusCode());
+
+            ClientManager.realm(adminClient.realm("test")).clientId("service-account-cl").setServiceAccountsEnabled(false);
+
+            response = oauth.doRefreshTokenRequest(response.getRefreshToken(), "secret1");
+            assertEquals(400, response.getStatusCode());
+        }
+        finally {
+            ClientManager.realm(adminClient.realm("test")).clientId("service-account-cl").setServiceAccountsEnabled(true);
+            UserRepresentation user = ClientManager.realm(adminClient.realm("test")).clientId("service-account-cl").getServiceAccountUser();
+            userId = user.getId();
+            userName = user.getUsername();
+        }
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java
index 3dfa580..154d659 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java
@@ -65,6 +65,12 @@ public class OIDCHybridResponseTypeCodeIDTokenTest extends AbstractOIDCResponseT
         Assert.assertNotNull(idToken.getCodeHash());
         Assert.assertEquals(idToken.getCodeHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getCode()));
 
+        // Financial API - Part 2: Read and Write API Security Profile
+        // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+        // Validate "s_hash"
+        Assert.assertNotNull(idToken.getStateHash());
+        Assert.assertEquals(idToken.getStateHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getState())); 
+
         // IDToken exchanged for the code
         IDToken idToken2 = sendTokenRequestAndGetIDToken(loginEvent);
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java
index 132195d..4ceb049 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java
@@ -66,6 +66,12 @@ public class OIDCHybridResponseTypeCodeIDTokenTokenTest extends AbstractOIDCResp
         Assert.assertNotNull(idToken.getCodeHash());
         Assert.assertEquals(idToken.getCodeHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getCode()));
 
+        // Financial API - Part 2: Read and Write API Security Profile
+        // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+        // Validate "s_hash"
+        Assert.assertNotNull(idToken.getStateHash());
+        Assert.assertEquals(idToken.getStateHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getState())); 
+        
         // IDToken exchanged for the code
         IDToken idToken2 = sendTokenRequestAndGetIDToken(loginEvent);
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
index 78ec0e7..a3f7e66 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
@@ -71,6 +71,10 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST_URI;
+
 /**
  * Test for supporting advanced parameters of OIDC specs (max_age, prompt, ...)
  *
@@ -376,6 +380,281 @@ public class OIDCAdvancedRequestParamsTest extends AbstractTestRealmKeycloakTest
     }
 
     // REQUEST & REQUEST_URI
+    
+    @Test
+    public void requestObjectNotRequiredNotProvided() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+        
+        // Send request without request object
+        // Assert that the request is accepted
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
+        Assert.assertNotNull(response.getCode());
+        Assert.assertEquals("mystate2", response.getState());
+        assertTrue(appPage.isCurrent());
+    }
+    
+    @Test
+    public void requestObjectNotRequiredProvidedInRequestParam() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+        
+        // Set up a request object
+        TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+        oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+        
+        // Send request object in "request" param
+        oauth.request(oidcClientEndpointsResource.getOIDCRequest());
+        // Assert that the request is accepted
+        OAuthClient.AuthorizationEndpointResponse response1 = oauth.doLogin("test-user@localhost", "password");
+        Assert.assertNotNull(response1.getCode());
+        Assert.assertEquals("mystate2", response1.getState());
+        assertTrue(appPage.isCurrent());
+    }
+    
+    @Test
+    public void requestObjectNotRequiredProvidedInRequestUriParam() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+        
+        // Set up a request object
+        TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+        oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+        
+        // Send request object reference in "request_uri" param
+        oauth.requestUri(TestApplicationResourceUrls.clientRequestUri());
+        // Assert that the request is accepted
+        OAuthClient.AuthorizationEndpointResponse response2 = oauth.doLogin("test-user@localhost", "password");
+        Assert.assertNotNull(response2.getCode());
+        Assert.assertEquals("mystate2", response2.getState());
+        assertTrue(appPage.isCurrent());
+    }
+    
+    @Test
+    public void requestObjectRequiredNotProvided() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI);
+        clientResource.update(clientRep);
+        
+        // Send request without request object
+        // Assert that the request is not accepted
+        oauth.openLoginForm();
+        Assert.assertTrue(errorPage.isCurrent());
+        assertEquals("Invalid Request", errorPage.getError());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
+    
+    @Test
+    public void requestObjectRequiredProvidedInRequestParam() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI);
+        clientResource.update(clientRep);
+        
+        // Set up a request object
+        TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+        oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+        
+        // Send request object in "request" param
+        oauth.request(oidcClientEndpointsResource.getOIDCRequest());
+        // Assert that the request is accepted
+        OAuthClient.AuthorizationEndpointResponse response1 = oauth.doLogin("test-user@localhost", "password");
+        Assert.assertNotNull(response1.getCode());
+        Assert.assertEquals("mystate2", response1.getState());
+        assertTrue(appPage.isCurrent());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
+    
+    @Test
+    public void requestObjectRequiredProvidedInRequestUriParam() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI);
+        clientResource.update(clientRep);
+        
+        // Set up a request object
+        TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+        oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+        
+        // Send request object reference in "request_uri" param
+        oauth.requestUri(TestApplicationResourceUrls.clientRequestUri());
+        // Assert that the request is accepted
+        OAuthClient.AuthorizationEndpointResponse response2 = oauth.doLogin("test-user@localhost", "password");
+        Assert.assertNotNull(response2.getCode());
+        Assert.assertEquals("mystate2", response2.getState());
+        assertTrue(appPage.isCurrent());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
+    
+    @Test
+    public void requestObjectRequiredAsRequestParamNotProvided() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST);
+        clientResource.update(clientRep);
+        
+        // Send request without request object
+        // Assert that the request is not accepted
+        oauth.openLoginForm();
+        Assert.assertTrue(errorPage.isCurrent());
+        assertEquals("Invalid Request", errorPage.getError());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
+    
+    @Test
+    public void requestObjectRequiredAsRequestParamProvidedInRequestParam() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST);
+        clientResource.update(clientRep);
+        
+        // Set up a request object
+        TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+        oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+        
+        // Send request object in "request" param
+        oauth.request(oidcClientEndpointsResource.getOIDCRequest());
+        // Assert that the request is accepted
+        OAuthClient.AuthorizationEndpointResponse response1 = oauth.doLogin("test-user@localhost", "password");
+        Assert.assertNotNull(response1.getCode());
+        Assert.assertEquals("mystate2", response1.getState());
+        assertTrue(appPage.isCurrent());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
+    
+    @Test
+    public void requestObjectRequiredAsRequestParamProvidedInRequestUriParam() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST);
+        clientResource.update(clientRep);
+        
+        // Set up a request object
+        TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+        oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+        
+        // Send request object reference in "request_uri" param
+        oauth.requestUri(TestApplicationResourceUrls.clientRequestUri());
+        // Assert that the request is accepted
+        oauth.openLoginForm();
+        Assert.assertTrue(errorPage.isCurrent());
+        assertEquals("Invalid Request", errorPage.getError());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
+    
+    @Test
+    public void requestObjectRequiredAsRequestUriParamNotProvided() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_URI);
+        clientResource.update(clientRep);
+        
+        // Send request without request object
+        // Assert that the request is not accepted
+        oauth.openLoginForm();
+        Assert.assertTrue(errorPage.isCurrent());
+        assertEquals("Invalid Request", errorPage.getError());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
+    
+    @Test
+    public void requestObjectRequiredAsRequestUriParamProvidedInRequestParam() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_URI);
+        clientResource.update(clientRep);
+        
+        // Set up a request object
+        TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+        oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+        
+        // Send request object in "request" param
+        oauth.request(oidcClientEndpointsResource.getOIDCRequest());
+        // Assert that the request is not accepted
+        oauth.openLoginForm();
+        Assert.assertTrue(errorPage.isCurrent());
+        assertEquals("Invalid Request", errorPage.getError());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
+    
+    @Test
+    public void requestObjectRequiredAsRequestUriParamProvidedInRequestUriParam() throws Exception {
+        oauth.stateParamHardcoded("mystate2");
+        // Set request object not required for client
+        ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+        ClientRepresentation clientRep = clientResource.toRepresentation();
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_URI);
+        clientResource.update(clientRep);
+        
+        // Set up a request object
+        TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+        oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+        
+        // Send request object reference in "request_uri" param
+        oauth.requestUri(TestApplicationResourceUrls.clientRequestUri());
+        // Assert that the request is accepted
+        OAuthClient.AuthorizationEndpointResponse response1 = oauth.doLogin("test-user@localhost", "password");
+        Assert.assertNotNull(response1.getCode());
+        Assert.assertEquals("mystate2", response1.getState());
+        assertTrue(appPage.isCurrent());
+        
+        // Revert requiring request object for client
+        OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+        clientResource.update(clientRep);
+    }
 
     @Test
     public void requestParamUnsigned() throws Exception {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
index 6bc7151..eb50949 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
@@ -5,6 +5,7 @@ import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -52,6 +53,12 @@ public class ClientManager {
             clientResource.update(app);
         }
 
+        public void setServiceAccountsEnabled(Boolean enabled) {
+            ClientRepresentation app = clientResource.toRepresentation();
+            app.setServiceAccountsEnabled(enabled);
+            clientResource.update(app);
+        }
+
         public void updateAttribute(String attribute, String value) {
             ClientRepresentation app = clientResource.toRepresentation();
             if (app.getAttributes() == null) {
@@ -132,5 +139,9 @@ public class ClientManager {
             }
             clientResource.update(app);
         }
+
+        public UserRepresentation getServiceAccountUser() {
+            return clientResource.getServiceAccountUser();
+        }
     }
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
index f0b2fe5..15d7bf7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
@@ -21,6 +21,7 @@ package org.keycloak.testsuite.x509;
 import org.jboss.logging.Logger;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.keycloak.admin.client.resource.AuthenticationManagementResource;
 import org.keycloak.authentication.AuthenticationFlow;
@@ -57,6 +58,7 @@ import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorC
 import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.IdentityMapperType.USER_ATTRIBUTE;
 import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN;
 import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN_CN;
+import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTALTNAME_EMAIL;
 import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_CN;
 import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_EMAIL;
 
@@ -100,6 +102,27 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
         return true;
     }
 
+    @BeforeClass
+    public static void onBeforeTestClass() {
+        if (Boolean.parseBoolean(System.getProperty("auth.server.jboss"))) {
+            String authServerHome = System.getProperty("auth.server.home");
+
+            if (authServerHome != null && System.getProperty("auth.server.ssl.required") != null) {
+                authServerHome = authServerHome + "/standalone/configuration";
+                StringBuilder cliArgs = new StringBuilder();
+
+                cliArgs.append("--ignore-ssl-errors=true ");
+                cliArgs.append("--web-security=false ");
+                cliArgs.append("--ssl-certificates-path=" + authServerHome + "/ca.crt ");
+                cliArgs.append("--ssl-client-certificate-file=" + authServerHome + "/client.crt ");
+                cliArgs.append("--ssl-client-key-file=" + authServerHome + "/client.key ");
+                cliArgs.append("--ssl-client-key-passphrase=secret ");
+
+                System.setProperty("keycloak.phantomjs.cli.args", cliArgs.toString());
+            }
+        }
+    }
+
     @Before
     public void configureFlows() {
         authMgmtResource = adminClient.realms().realm(REALM_NAME).flows();
@@ -301,6 +324,13 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
                 .setUserIdentityMapperType(USERNAME_EMAIL);
     }
 
+    protected static X509AuthenticatorConfigModel createLoginSubjectAltNameEmail2UsernameOrEmailConfig() {
+        return new X509AuthenticatorConfigModel()
+                .setConfirmationPageAllowed(true)
+                .setMappingSourceType(SUBJECTALTNAME_EMAIL)
+                .setUserIdentityMapperType(USERNAME_EMAIL);
+    }
+
     protected static X509AuthenticatorConfigModel createLoginSubjectEmailWithKeyUsage(String keyUsage) {
         return createLoginSubjectEmail2UsernameOrEmailConfig()
                 .setKeyUsage(keyUsage);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginSubjectAltNameEmailTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginSubjectAltNameEmailTest.java
new file mode 100644
index 0000000..e8cfc37
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginSubjectAltNameEmailTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.x509;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel;
+import org.keycloak.events.Details;
+import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.x509.X509IdentityConfirmationPage;
+
+/**
+ * @author <a href="mailto:brat000012001@gmail.com">Peter Nalyvayko</a>
+ * @version $Revision: 1 $
+ * @date 8/12/2016
+ */
+
+public class X509BrowserLoginSubjectAltNameEmailTest extends AbstractX509AuthenticationTest {
+
+    @Page
+    protected AppPage appPage;
+
+    @Page
+    protected X509IdentityConfirmationPage loginConfirmationPage;
+
+    @Page
+    protected LoginPage loginPage;
+
+    @BeforeClass
+    public static void onBeforeTestClass() {
+        if (Boolean.parseBoolean(System.getProperty("auth.server.jboss"))) {
+            String authServerHome = System.getProperty("auth.server.home");
+
+            if (authServerHome != null && System.getProperty("auth.server.ssl.required") != null) {
+                authServerHome = authServerHome + "/standalone/configuration";
+                StringBuilder cliArgs = new StringBuilder();
+
+                cliArgs.append("--ignore-ssl-errors=true ");
+                cliArgs.append("--web-security=false ");
+                cliArgs.append("--ssl-certificates-path=" + authServerHome + "/ca.crt ");
+                cliArgs.append("--ssl-client-certificate-file=" + authServerHome + "/certs/clients/test-user-san-email@localhost.cert.pem ");
+                cliArgs.append("--ssl-client-key-file=" + authServerHome + "/certs/clients/test-user@localhost.key.pem ");
+                cliArgs.append("--ssl-client-key-passphrase=password");
+
+                System.setProperty("keycloak.phantomjs.cli.args", cliArgs.toString());
+            }
+        }
+    }
+
+    private void login(X509AuthenticatorConfigModel config, String userId, String username, String attemptedUsername) {
+
+        AuthenticatorConfigRepresentation cfg = newConfig("x509-browser-config", config.getConfig());
+        String cfgId = createConfig(browserExecution.getId(), cfg);
+        Assert.assertNotNull(cfgId);
+
+        loginConfirmationPage.open();
+
+        Assert.assertTrue(loginConfirmationPage.getSubjectDistinguishedNameText().equals("CN=test-user, OU=Keycloak, O=Red Hat, L=Boston, ST=MA, C=US"));
+        Assert.assertEquals(username, loginConfirmationPage.getUsernameText());
+
+        loginConfirmationPage.confirm();
+
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+        Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
+
+        events.expectLogin()
+                .user(userId)
+                .detail(Details.USERNAME, attemptedUsername)
+                .removeDetail(Details.REDIRECT_URI)
+                .assertEvent();
+    }
+
+    @Test
+    public void loginAsUserFromCertSubjectEmail() {
+        login(createLoginSubjectAltNameEmail2UsernameOrEmailConfig(), userId, "test-user@localhost", "test-user@localhost");
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
index 2b5c24f..e45dc60 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
@@ -33,18 +33,20 @@
         <property name="htmlUnit.version">${htmlUnitBrowserVersion}</property>
         <property name="htmlUnitWebClientOptions">cssEnabled=false;historyPageCacheLimit=1</property>
 
-        <!-- phantomjs -->
-        <property name="phantomjs.cli.args">${phantomjs.cli.args}</property>
-
         <!-- firefox -->
         <property name="firefox_binary">${firefox_binary}</property>
         <property name="firefoxLogLevel">OFF</property>
         <property name="firefoxLegacy">${firefoxLegacyDriver}</property>
 
         <!-- chrome -->
+        <property name="chromeBinary">${chromeBinary}</property>
         <property name="chromeArguments">${chromeArguments}</property>
     </extension>
 
+    <extension qualifier="drone">
+       <property name="instantiationTimeoutInSeconds">${droneInstantiationTimeoutInSeconds}</property>
+    </extension>
+    
     <extension qualifier="graphene">
         <property name="waitGuiInterval">5</property>
         <property name="waitAjaxInterval">5</property>
@@ -58,7 +60,6 @@
         <property name="firefox_binary">${firefox_binary}</property>
         <property name="chromeDriverBinary">${webdriver.chrome.driver}</property>
         <property name="chromeArguments">${js.chromeArguments}</property>
-        <property name="phantomjs.cli.args">${phantomjs.cli.args} --ssl-certificates-path=${client.certificate.ca.path} --ssl-client-certificate-file=${client.certificate.file} --ssl-client-key-file=${client.key.file} --ssl-client-key-passphrase=${client.key.passphrase}</property>
     </extension>
 
     <extension qualifier="graphene-secondbrowser">
@@ -383,6 +384,7 @@
                     -Djboss.node.name=auth-server-${node.name}-cross-dc-0_1
                     -Dauth.server.truststore=${auth.server.truststore}
                     -Dauth.server.truststore.password=${auth.server.truststore.password}
+                    -Dkeycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}
                 </property>
                 <property name="javaVmArguments">
                     -Djava.net.preferIPv4Stack=true
@@ -408,6 +410,7 @@
                     -Djboss.node.name=auth-server-${node.name}-cross-dc-0_2-manual
                     -Dauth.server.truststore=${auth.server.truststore}
                     -Dauth.server.truststore.password=${auth.server.truststore.password}
+                    -Dkeycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}
                 </property>
                 <property name="javaVmArguments">
                     -Djava.net.preferIPv4Stack=true
@@ -434,6 +437,7 @@
                     -Djboss.node.name=auth-server-${node.name}-cross-dc-1_1
                     -Dauth.server.truststore=${auth.server.truststore}
                     -Dauth.server.truststore.password=${auth.server.truststore.password}
+                    -Dkeycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}
                 </property>
                 <property name="javaVmArguments">
                     -Djava.net.preferIPv4Stack=true
@@ -459,6 +463,7 @@
                     -Djboss.node.name=auth-server-${node.name}-cross-dc-1_2-manual
                     -Dauth.server.truststore=${auth.server.truststore}
                     -Dauth.server.truststore.password=${auth.server.truststore.password}
+                    -Dkeycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}
                 </property>
                 <property name="javaVmArguments">
                     -Djava.net.preferIPv4Stack=true
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json
index 1d60090..5bc4976 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json
@@ -61,7 +61,7 @@
         "mavenArtifactVersion": "${project.version}",
         "mavenArtifactId": "photoz-authz-policy",
         "sessionName": "MainOwnerSession",
-        "mavenArtifactGroupId": "org.keycloak",
+        "mavenArtifactGroupId": "org.keycloak.testsuite",
         "moduleName": "PhotozAuthzOwnerPolicy",
         "scannerPeriod": "1",
         "scannerPeriodUnit": "Hours"
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl
index 67a494a..e6a96da 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl
@@ -65,6 +65,7 @@
                     <property name="javaVmArguments">
                         -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7901
                         ${app.server.memory.settings}
+                        ${app.server.cluster.tests.memory.settings}
                         -Djava.net.preferIPv4Stack=true
                     </property>
                     <property name="managementProtocol">${app.server.management.protocol}</property>
@@ -89,6 +90,7 @@
                     <property name="javaVmArguments">
                         -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7902
                         ${app.server.memory.settings}
+                        ${app.server.cluster.tests.memory.settings}
                         -Djava.net.preferIPv4Stack=true
                     </property>
                     <property name="managementProtocol">${app.server.management.protocol}</property>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java
index 74ec300..eb41e03 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java
@@ -20,6 +20,7 @@ import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable;
 import org.keycloak.testsuite.arquillian.annotation.*;
 
 import java.io.*;
+import java.util.concurrent.TimeoutException;
 
 import org.keycloak.testsuite.adapter.servlet.cluster.AbstractSAMLAdapterClusterTest;
 import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet;
@@ -30,6 +31,7 @@ import org.jboss.shrinkwrap.api.spec.WebArchive;
 import org.wildfly.extras.creaper.core.*;
 import org.wildfly.extras.creaper.core.online.*;
 import org.wildfly.extras.creaper.core.online.operations.*;
+import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
 
 
 /**
@@ -52,13 +54,14 @@ public class EAPSAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
     }
 
     @Override
-    protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, CliException, NumberFormatException {
+    protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, NumberFormatException, TimeoutException, InterruptedException {
         log.infov("Preparing worker node ({0} @ {1})", nodeIndex, managementPort);
 
         OnlineManagementClient clientWorkerNodeClient = ManagementClient.online(OnlineOptions
           .standalone()
           .hostAndPort("localhost", managementPort)
           .build());
+        Administration administration = new Administration(clientWorkerNodeClient);
         Operations op = new Operations(clientWorkerNodeClient);
 
         Batch b = new Batch();
@@ -86,7 +89,8 @@ public class EAPSAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
         op.add(Address.extension("org.keycloak.keycloak-saml-adapter-subsystem"), Values.of("module", "org.keycloak.keycloak-saml-adapter-subsystem"));
         op.add(Address.subsystem("keycloak-saml"));
 
-        clientWorkerNodeClient.execute("reload");
+        //clientWorkerNodeClient.execute("reload");
+        administration.reload();
 
         log.infov("Worker node ({0}) Prepared", managementPort);
     }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java
index b52a8de..37a7aa6 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java
@@ -20,6 +20,7 @@ import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable;
 import org.keycloak.testsuite.arquillian.annotation.*;
 
 import java.io.*;
+import java.util.concurrent.TimeoutException;
 
 import org.keycloak.testsuite.adapter.servlet.cluster.AbstractSAMLAdapterClusterTest;
 import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet;
@@ -31,6 +32,7 @@ import org.junit.Assert;
 import org.wildfly.extras.creaper.core.*;
 import org.wildfly.extras.creaper.core.online.*;
 import org.wildfly.extras.creaper.core.online.operations.*;
+import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
 
 import static org.keycloak.testsuite.adapter.AbstractServletsAdapterTest.samlServletDeployment;
 
@@ -54,7 +56,7 @@ public class EAP6SAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
     }
 
     @Override
-    protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, CliException, NumberFormatException {
+    protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, NumberFormatException, TimeoutException, InterruptedException {
         log.infov("Preparing worker node ({0} @ {1})", nodeIndex, managementPort);
 
         OnlineManagementClient clientWorkerNodeClient = ManagementClient.online(OnlineOptions
@@ -62,6 +64,7 @@ public class EAP6SAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
           .hostAndPort("localhost", managementPort)
           .protocol(ManagementProtocol.REMOTE)
           .build());
+        Administration administration = new Administration(clientWorkerNodeClient);
         Operations op = new Operations(clientWorkerNodeClient);
 
         Batch b = new Batch();
@@ -94,7 +97,8 @@ public class EAP6SAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
         Assert.assertTrue(op.add(Address.extension("org.keycloak.keycloak-saml-adapter-subsystem"), Values.of("module", "org.keycloak.keycloak-saml-adapter-subsystem")).isSuccess());
         Assert.assertTrue(op.add(Address.subsystem("keycloak-saml")).isSuccess());
 
-        clientWorkerNodeClient.execute("reload");
+        //clientWorkerNodeClient.execute("reload");
+        administration.reload();
 
         log.infov("Worker node ({0}) Prepared", managementPort);
     }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java
index 5735a6a..78f86ae 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java
@@ -20,6 +20,7 @@ import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable;
 import org.keycloak.testsuite.arquillian.annotation.*;
 
 import java.io.*;
+import java.util.concurrent.TimeoutException;
 
 import org.keycloak.testsuite.adapter.servlet.cluster.AbstractSAMLAdapterClusterTest;
 import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet;
@@ -30,6 +31,7 @@ import org.jboss.shrinkwrap.api.spec.WebArchive;
 import org.wildfly.extras.creaper.core.*;
 import org.wildfly.extras.creaper.core.online.*;
 import org.wildfly.extras.creaper.core.online.operations.*;
+import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
 
 import static org.keycloak.testsuite.adapter.AbstractServletsAdapterTest.samlServletDeployment;
 
@@ -53,13 +55,14 @@ public class WildflySAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTes
     }
 
     @Override
-    protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, CliException, NumberFormatException {
+    protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, NumberFormatException, TimeoutException, InterruptedException {
         log.infov("Preparing worker node ({0} @ {1})", nodeIndex, managementPort);
 
         OnlineManagementClient clientWorkerNodeClient = ManagementClient.online(OnlineOptions
           .standalone()
           .hostAndPort("localhost", managementPort)
           .build());
+        Administration administration = new Administration(clientWorkerNodeClient);
         Operations op = new Operations(clientWorkerNodeClient);
 
         Batch b = new Batch();
@@ -87,7 +90,8 @@ public class WildflySAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTes
         op.add(Address.extension("org.keycloak.keycloak-saml-adapter-subsystem"), Values.of("module", "org.keycloak.keycloak-saml-adapter-subsystem"));
         op.add(Address.subsystem("keycloak-saml"));
 
-        clientWorkerNodeClient.execute("reload");
+        //clientWorkerNodeClient.execute("reload");
+        administration.reload();
 
         log.infov("Worker node ({0}) Prepared", managementPort);
     }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java
index f35217c..42cde44 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java
@@ -16,7 +16,6 @@
  */
 package org.keycloak.testsuite.adapter.example.authorization;
 
-import org.keycloak.testsuite.adapter.example.authorization.AbstractPhotozExampleAdapterTest;
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
 
 /**
diff --git a/testsuite/integration-arquillian/tests/other/adapters/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/pom.xml
index a90ff60..38b6e69 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/pom.xml
@@ -51,6 +51,8 @@
         <app.server.management.port.jmx>10199</app.server.management.port.jmx>
         <app.server.startup.timeout>60</app.server.startup.timeout>
         <app.server.memory.settings>-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</app.server.memory.settings>
+        <!-- Cluster tests are failing with -Xmx512 for insufficient physical memory -->
+        <app.server.cluster.tests.memory.settings>-Xmx384m</app.server.cluster.tests.memory.settings>
 
         <!--debug properties-->
         <app.server.debug.port>5006</app.server.debug.port>
@@ -218,6 +220,7 @@
 
                                 <app.server.startup.timeout>${app.server.startup.timeout}</app.server.startup.timeout>
                                 <app.server.memory.settings>${app.server.memory.settings}</app.server.memory.settings>
+                                <app.server.cluster.tests.memory.settings>${app.server.cluster.tests.memory.settings}</app.server.cluster.tests.memory.settings>
                                 <app.server.jboss.jvm.debug.args>${app.server.jboss.jvm.debug.args}</app.server.jboss.jvm.debug.args>
                                 
                                 <app.server.reverse-proxy.port.offset>${app.server.reverse-proxy.port.offset}</app.server.reverse-proxy.port.offset>
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java
index a1fbb60..0e6501f 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java
@@ -88,7 +88,7 @@ public class RulePolicyManagementTest extends AbstractAuthorizationSettingsTest 
 
         expected.setName(name);
         expected.setDescription("description");
-        expected.setArtifactGroupId("org.keycloak");
+        expected.setArtifactGroupId("org.keycloak.testsuite");
         expected.setArtifactId("photoz-authz-policy");
         expected.setArtifactVersion(Version.VERSION);
         expected.setModuleName("PhotozAuthzOwnerPolicy");
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index 04a9583..ea76512 100755
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -102,15 +102,16 @@
 
         <browser>htmlUnit</browser>
         <webdriverDownloadBinaries>true</webdriverDownloadBinaries>
+        <droneInstantiationTimeoutInSeconds>60</droneInstantiationTimeoutInSeconds>
         <github.username/>
         <github.secretToken/>
         <ieDriverArch/>
         <js.browser>phantomjs</js.browser>
         <js.chromeArguments>--headless</js.chromeArguments>
         <htmlUnitBrowserVersion>chrome</htmlUnitBrowserVersion>
-        <phantomjs.cli.args>--ignore-ssl-errors=true --web-security=false --ssl-certificates-path=${client.certificate.ca.path} --ssl-client-certificate-file=${client.certificate.file} --ssl-client-key-file=${client.key.file} --ssl-client-key-passphrase=${client.key.passphrase}</phantomjs.cli.args>
         <firefox_binary>/usr/bin/firefox</firefox_binary>
         <firefoxLegacyDriver>true</firefoxLegacyDriver>
+        <chromeBinary/>
         <chromeArguments/>
 
         <frontend.console.output>true</frontend.console.output>
@@ -278,13 +279,14 @@
                             <js.chromeArguments>${js.chromeArguments}</js.chromeArguments>
                             <htmlUnitBrowserVersion>${htmlUnitBrowserVersion}</htmlUnitBrowserVersion>
                             <webdriverDownloadBinaries>${webdriverDownloadBinaries}</webdriverDownloadBinaries>
+                            <droneInstantiationTimeoutInSeconds>${droneInstantiationTimeoutInSeconds}</droneInstantiationTimeoutInSeconds>
 
                             <github.username>${github.username}</github.username>
                             <github.secretToken>${github.secretToken}</github.secretToken>
                             <ieDriverArch>${ieDriverArch}</ieDriverArch>
 
                             <firefox_binary>${firefox_binary}</firefox_binary>
-                            <phantomjs.cli.args>${phantomjs.cli.args}</phantomjs.cli.args>
+                            <chromeBinary>${chromeBinary}</chromeBinary>
                             <chromeArguments>${chromeArguments}</chromeArguments>
 
                             <firefoxLegacyDriver>${firefoxLegacyDriver}</firefoxLegacyDriver>
@@ -606,6 +608,8 @@
                                 <auth.server.crossdc11.home>${auth.server.crossdc11.home}</auth.server.crossdc11.home>
                                 <auth.server.crossdc12.home>${auth.server.crossdc12.home}</auth.server.crossdc12.home>
 
+                                <keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}</keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>
+
                                 <!--8101-->
                                 <auth.server.crossdc01.port.offset>21</auth.server.crossdc01.port.offset>
                                 <!--8102-->
@@ -656,6 +660,7 @@
                 <cache.server.jboss>true</cache.server.jboss>
                 <cache.server.config.dir>${cache.server.home}/standalone/configuration</cache.server.config.dir>
                 <keycloak.testsuite.logging.pattern>%d{HH:mm:ss,SSS} [%t] %-5p [%c{1.}] %m%n</keycloak.testsuite.logging.pattern>
+                <keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>false</keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>
             </properties>
             <dependencies>
                 <dependency>
@@ -728,6 +733,7 @@
                 <cache.server.jboss>true</cache.server.jboss>
                 <cache.server.config.dir>${cache.server.home}/standalone/configuration</cache.server.config.dir>
                 <keycloak.testsuite.logging.pattern>%d{HH:mm:ss,SSS} [%t] %-5p [%c{1.}] %m%n</keycloak.testsuite.logging.pattern>
+                <keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>true</keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>
             </properties>
             <dependencies>
                 <dependency>
diff --git a/testsuite/integration-deprecated/pom.xml b/testsuite/integration-deprecated/pom.xml
index e9cc992..b47e88a 100755
--- a/testsuite/integration-deprecated/pom.xml
+++ b/testsuite/integration-deprecated/pom.xml
@@ -280,6 +280,11 @@
             <artifactId>mariadb-java-client</artifactId>
             <version>${mariadb.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak.testsuite</groupId>
+            <artifactId>integration-arquillian-test-apps-servlets</artifactId>
+            <version>4.0.0.CR1-SNAPSHOT</version>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
index 5ac5722..6e1831d 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
@@ -27,7 +27,7 @@ import org.keycloak.saml.common.constants.JBossSAMLConstants;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 import org.keycloak.saml.common.util.DocumentUtil;
 import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
-import org.keycloak.testsuite.samlfilter.SamlAdapterTest;
+import org.keycloak.testsuite.helper.adapter.SamlKeycloakRule;
 import org.w3c.dom.Document;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
@@ -73,10 +73,10 @@ public class SamlEcpProfileTest {
     protected String APP_SERVER_BASE_URL = "http://localhost:8081";
 
     @ClassRule
-    public static org.keycloak.testsuite.samlfilter.SamlKeycloakRule keycloakRule = new org.keycloak.testsuite.samlfilter.SamlKeycloakRule() {
+    public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
         @Override
         public void initWars() {
-            ClassLoader classLoader = SamlAdapterTest.class.getClassLoader();
+            ClassLoader classLoader = SamlEcpProfileTest.class.getClassLoader();
 
             initializeSamlSecuredWar("/keycloak-saml/ecp/ecp-sp", "/ecp-sp",  "ecp-sp.war", classLoader);
         }
diff --git a/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index 064d46e..67cc922 100755
--- a/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.openqa.selenium.WebDriver;
 
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 77a1484..0a0f741 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index 064d46e..67cc922 100755
--- a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.openqa.selenium.WebDriver;
 
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 1f59ff9..5dbfdc0 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index f1e72a4..9529c0f 100755
--- a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.openqa.selenium.WebDriver;
 
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index f1e72a4..9529c0f 100644
--- a/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.openqa.selenium.WebDriver;
 
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty94/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index f1e72a4..9529c0f 100644
--- a/testsuite/jetty/jetty94/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty94/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.openqa.selenium.WebDriver;
 
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/performance/keycloak/pom.xml b/testsuite/performance/keycloak/pom.xml
index f9404d9..2e1d1b5 100644
--- a/testsuite/performance/keycloak/pom.xml
+++ b/testsuite/performance/keycloak/pom.xml
@@ -37,7 +37,7 @@
     <properties>
         <server.groupId>org.keycloak</server.groupId>
         <server.artifactId>keycloak-server-dist</server.artifactId>
-        <server.version>${product.version}</server.version>
+        <!-- `server.version` is defined one level up -->
         <server.unpacked.folder.name>keycloak-${server.version}</server.unpacked.folder.name>
         <server.unpacked.home>${project.build.directory}/${server.unpacked.folder.name}</server.unpacked.home>
         
diff --git a/testsuite/performance/pom.xml b/testsuite/performance/pom.xml
index 089fcd0..5865c06 100644
--- a/testsuite/performance/pom.xml
+++ b/testsuite/performance/pom.xml
@@ -32,6 +32,7 @@
     <packaging>pom</packaging>
     
     <properties>
+        <server.version>${product.version}</server.version>
         <management.user/>
         <management.user.password/>
     </properties>
diff --git a/testsuite/performance/README.md b/testsuite/performance/README.md
index 24b12ba..67f01bf 100644
--- a/testsuite/performance/README.md
+++ b/testsuite/performance/README.md
@@ -26,9 +26,8 @@ mvn clean install
 
 # Make sure your Docker daemon is running THEN
 mvn verify -Pprovision
-mvn verify -Pgenerate-data -Ddataset=100u -DnumOfWorkers=10 -DhashIterations=100
-mvn verify -Ptest -Ddataset=100u -DusersPerSec=4.5 -DrampUpPeriod=10 -DuserThinkTime=0 -DbadLoginAttempts=1 -DrefreshTokenCount=1 -DmeasurementPeriod=60 -DfilterResults=true
-
+mvn verify -Pgenerate-data -Ddataset=100u2c -DnumOfWorkers=10 -DhashIterations=100
+mvn verify -Ptest -Ddataset=100u2c -DusersPerSec=2 -DrampUpPeriod=10 -DuserThinkTime=0 -DbadLoginAttempts=1 -DrefreshTokenCount=1 -DmeasurementPeriod=60 -DfilterResults=true
 ```
 
 Now open the generated report in a browser - the link to .html file is displayed at the end of the test.
@@ -40,7 +39,7 @@ mvn verify -Pteardown
 
 You can perform all phases in a single run:
 ```
-mvn verify -Pprovision,generate-data,test,teardown -Ddataset=100u -DnumOfWorkers=10 -DhashIterations=100 -DusersPerSec=5 -DrampUpPeriod=10
+mvn verify -Pprovision,generate-data,test,teardown -Ddataset=100u2c -DnumOfWorkers=10 -DhashIterations=100 -DusersPerSec=4 -DrampUpPeriod=10
 ```
 Note: The order in which maven profiles are listed does not determine the order in which profile related plugins are executed. `teardown` profile always executes last.
 
@@ -49,21 +48,44 @@ Keep reading for more information.
 
 ## Provisioning
 
-### Available provisioners:
+### Provision
 
-- `docker-compose` **Default.** See [`README.docker-compose.md`](README.docker-compose.md) for more details.
+#### Provisioners
 
-### Provision
+Depending on the target environment different provisioners may be used.
+Provisioner can be selected via property `-Dprovisioner=PROVISIONER`. 
 
-Usage: `mvn verify -Pprovision [-Dprovisioner=<PROVISIONER>] [-D<PARAMETER>=<VALUE>] …`. 
+Default value is `docker-compose` which is intended for testing on a local docker host.
+This is currently the only implemented option. See [`README.docker-compose.md`](README.docker-compose.md) for more details.
 
 #### Deployment Types
 
-- Single node: `mvn verify -Pprovision`
-- Cluster: `mvn verify -Pprovision,cluster [-Dkeycloak.scale=N] [-Dkeycloak.cpusets="cpuset1 cpuset2 … cpusetM"]`. `N ∈ {1 .. M}`.
-- Cross-DC: `mvn verify -Pprovision,crossdc [-Dkeycloak.dc1.scale=K] [-Dkeycloak.dc2.scale=L] [-Dkeycloak.dc1.cpusets=…] [-Dkeycloak.dc2.cpusets=…]`
+Different types of deployment can be provisioned.
+The default deployment is `singlenode` with only a single instance of Keycloak server and a database.
+Additional options are `cluster` and `crossdc` which can be enabled with a profile (see below).
+
+#### Usage
+
+Usage: `mvn verify -P provision[,DEPLOYMENT_PROFILE] [-Dprovisioning.properties=NAMED_PROPERTY_SET]`.
+
+The properties are loaded from `tests/parameters/provisioning/${provisioning.properties}.properties` file.
+Individual parameters can be overriden from command line via `-D` params.
+
+Default property set is `docker-compose/4cpus/singlenode`.
+
+To load a custom properties file specify `-Dprovisioning.properties.file=ABSOLUTE_PATH_TO_FILE` instead of `-Dprovisioning.properties`.
+This file needs to contain all properties required by the specific combination of provisioner and deployment type.
+See examples in folder `tests/parameters/provisioning/docker-compose/4cpus`.
+
+Available parameters are described in [`README.provisioning-parameters.md`](README.provisioning-parameters.md).
+
+#### Examples:
+- Provision a single-node deployment with docker-compose: `mvn verify -P provision`
+- Provision a cluster deployment with docker-compose: `mvn verify -P provision,cluster`
+- Provision a cluster deployment with docker-compose, overriding some properties: `mvn verify -P provision,cluster -Dkeycloak.scale=2 -Dlb.worker.task-max-threads=32`
+- Provision a cross-DC deployment with docker-compose: `mvn verify -P provision,crossdc`
+- Provision a cross-DC deployment with docker-compose using a custom properties file: `mvn verify -P provision,crossdc -Dprovisioning.properties.file=/tmp/custom-crossdc.properties`
 
-All available parameters are described in [`README.provisioning-parameters.md`](README.provisioning-parameters.md).
 
 #### Provisioned System
 
@@ -71,8 +93,9 @@ The `provision` operation will produce a `provisioned-system.properties` inside 
 with information about the provisioned system such as the type of deployment and URLs of Keycloak servers and load balancers.
 This information is then used by operations `generate-data`, `import-dump`, `test`, `teardown`.
 
-Provisioning can be run multiple times with different parameters. The system will be updated/reprovisioned based on the new parameters.
-However when switching between different deployment types (e.g. from `singlenode` to `cluster`) it is always necessary 
+Provisioning operation is idempotent for a specific combination of provisioner+deployment. 
+When running multiple times the system will be simply updated based on the new parameters.
+However when switching between different provisioiners or deployment types it is **always necessary** 
 to tear down the currently running system.
 
 **Note:** When switching deployment type from `singlenode` or `cluster` to `crossdc` (or the other way around) 
@@ -80,6 +103,13 @@ it is necessary to update the generated Keycloak server configuration (inside `k
 adding a `clean` goal to the provisioning command like so: `mvn clean verify -Pprovision …`. It is *not* necessary to update this configuration 
 when switching between `singlenode` and `cluster` deployments.
 
+### Collect Artifacts
+
+Usage: `mvn verify -Pcollect`
+
+Collects artifacts such as logs from the provisioned system and stores them in `tests/target/collected-artifacts/${deployment}-TIMESTAMP/`.
+When used in combination with teardown (see below) the artifacts are collected just before the system is torn down.
+
 ### Teardown
 
 Usage: `mvn verify -Pteardown [-Dprovisioner=<PROVISIONER>]`
@@ -92,18 +122,19 @@ because it contains the `provisioned-system.properties` with information about t
 
 ### Generate Test Data
 
-Usage: `mvn verify -Pgenerate-data [-Ddataset=DATASET] [-D<dataset.property>=<value>]`.
+Usage: `mvn verify -P generate-data [-Ddataset=NAMED_PROPERTY_SET] [-DnumOfWorkers=N]`. The default dataset is `2u2c`. Workers default to `1`.
 
-Dataset properties are loaded from `datasets/${dataset}.properties` file. Individual properties can be overriden by specifying `-D` params.
+The parameters are loaded from `tests/parameters/datasets/${dataset}.properties` file.
+Individual properties can be overriden from command line via `-D` params.
 
-Dataset data is first generated as a .json file, and then imported into Keycloak via Admin Client REST API.
+To use a custom properties file specify `-Ddataset.properties.file=ABSOLUTE_PATH_TO_FILE` instead of `-Ddataset`.
 
-#### Dataset Properties
+#### Dataset Parameters
 
 | Property | Description | Value in the Default Dataset |
 | --- | --- | --- | 
 | `numOfRealms` | Number of realms to be created. | `1`  |
-| `usersPerRealm` | Number of users per realm. | `100`  |
+| `usersPerRealm` | Number of users per realm. | `2`  |
 | `clientsPerRealm` | Number of clients per realm. | `2`  |
 | `realmRoles` | Number of realm-roles per realm. | `2`  |
 | `realmRolesPerUser` | Number of realm-roles assigned to a created user. Has to be less than or equal to `realmRoles`. | `2`  |
@@ -113,53 +144,73 @@ Dataset data is first generated as a .json file, and then imported into Keycloak
 
 
 #### Examples:
-- `mvn verify -Pgenerate-data` - generate default dataset
-- `mvn verify -Pgenerate-data -DusersPerRealm=5` - generate default dataset, override the `usersPerRealm` property
-- `mvn verify -Pgenerate-data -Ddataset=100u` - generate `100u` dataset
-- `mvn verify -Pgenerate-data -Ddataset=100r/default` - generate dataset based on `datasets/100r/default.properties`
+- Generate the default dataset. `mvn verify -P generate-data`
+- Generate the `100u2c` dataset. `mvn verify -P generate-data -Ddataset=100u2c`
+- Generate the `100u2c` dataset but override some parameters. `mvn verify -P generate-data -Ddataset=100u2c -DclientRolesPerUser=5 -DclientRolesPerClient=5`
+
+#### Export Database
 
-#### Export / Import Database Dump
+To export the generated data to a data-dump file enable profile `-P export-dump`. This will create a `${DATASET}.sql.gz` file next to the dataset properties file.
 
-To speed up dataset initialization part, it is possible to pass `-Dexport-dump` option to have the generated dataset
-exported right after it has been generated. Then, if there is a data dump file available then `-Pimport-dump` 
-can be used to import the data directly into the database, bypassing Keycloak server completely.
+Example: `mvn verify -P generate-data,export-dump -Ddataset=100u2c`
 
-**Usage:** `mvn verify -Pimport-dump [-Ddataset=DATASET]`
+#### Import Database
 
-**For example:**
-- `mvn verify -Pgenerate-data -Ddataset=100u -Dexport-dump` will generate data based on `datasets/100u.properties` and export a database dump to a file: `datasets/100u.sql.gz`.
-- `mvn verify -Pimport-dump -Ddataset=100u` will import the database dump from a file: `datasets/100u.sql.gz`, and reboot the server(s)
+To import data from an existing data-dump file use profile `-P import-dump`.
+
+Example: `mvn verify -P import-dump -Ddataset=100u2c`
+
+If the dump file doesn't exist locally the script will attempt to download it from `${db.dump.download.site}` which defaults to `https://downloads.jboss.org/keycloak-qe/${server.version}` 
+with `server.version` defaulting to `${project.version}` from `pom.xml`.
+
+**Warning:** Don't override dataset parameters (with `-Dparam=value`) when running export/import because then the contents of dump file might not match the properties file.
 
 
 ### Run Tests
 
-Usage: `mvn verify -Ptest[,cluster] [-DtestParameter=value]`.
+Usage: `mvn verify -P test [-Dtest.properties=NAMED_PROPERTY_SET]`. Default property set is `basic-oidc`.
+
+The parameters are loaded from `tests/parameters/test/${test.properties}.properties` file.
+Individual properties can be overriden from command line via `-D` params.
+
+To use a custom properties file specify `-Dtest.properties.file=ABSOLUTE_PATH_TO_FILE` instead of `-Dtest.properties`.
 
-#### Common Parameters
+When running the tests it is also necessary to define a dataset to use. Usage is described in the section above.
+
+#### Common Test Run Parameters
 
 | Parameter | Description | Default Value |
 | --- | --- | --- | 
 | `gatling.simulationClass` | Classname of the simulation to be run. | `keycloak.BasicOIDCSimulation`  |
 | `dataset` | Name of the dataset to use. (Individual dataset properties can be overridden with `-Ddataset.property=value`.) | `default` |
-| `usersPerSec` | Arrival rate of new users per second. Can be a floating point number. | `1.0` |
-| `rampUpPeriod` | Period during which the users will be ramped up. (seconds) | `0` |
-| `warmUpPeriod` | Period with steady number of users intended for the system under test to warm up. (seconds) | `0` |
+| `usersPerSec` | Arrival rate of new users per second. Can be a floating point number. | `1.0` for BasicOIDCSimulation, `0.2` for AdminConsoleSimulation |
+| `rampUpPeriod` | Period during which the users will be ramped up. (seconds) | `15` |
+| `warmUpPeriod` | Period with steady number of users intended for the system under test to warm up. (seconds) | `15` |
 | `measurementPeriod` | A measurement period after the system is warmed up. (seconds) | `30` |
 | `filterResults` | Whether to filter out requests which are outside of the `measurementPeriod`. | `false` |
 | `userThinkTime` | Pause between individual scenario steps. | `5` |
 | `refreshTokenPeriod`| Period after which token should be refreshed. | `10` |
 
-#### Addtional Parameters of `keycloak.BasicOIDCSimulation`
+#### Test Run Parameters specific to `BasicOIDCSimulation`
 
 | Parameter | Description | Default Value |
 | --- | --- | --- | 
 | `badLoginAttempts` | | `0`  |
 | `refreshTokenCount` | | `0` |
 
+#### Examples:
+
+- Run test with default test and dataset parameters:
+
+`mvn verify -P test`
+
+- Run test specific test and dataset parameters:
 
-Example:
+`mvn verify -P test -Dtest.properties=basic-oidc -Ddataset=100u2c`
 
-`mvn verify -Ptest -Dgatling.simulationClass=keycloak.AdminConsoleSimulation -Ddataset=100u -DusersPerSec=1 -DmeasurementPeriod=60 -DuserThinkTime=0 -DrefreshTokenPeriod=15`
+- Run test with specific test and dataset parameters, overriding some from command line:
+
+`mvn verify -P test -Dtest.properties=admin-console -Ddataset=100u2c -DrampUpPeriod=30 -DwarmUpPeriod=60 -DusersPerSec=0.3`
 
 
 ## Monitoring
@@ -202,32 +253,6 @@ To compress the binary output with bzip add `-Dbzip=true` to the commandline.
 
 Results will be stored in folder: `tests/target/sar`.
 
-## Examples
-
-### Single-node
-
-- Provision single node of KC + DB, generate data, run test, and tear down the provisioned system:
-
-    `mvn verify -Pprovision,generate-data,test,teardown -Ddataset=100u -DusersPerSec=5`
-
-- Provision single node of KC + DB, generate data, no test, no teardown:
-
-    `mvn verify -Pprovision,generate-data -Ddataset=100u`
-
-- Run test against provisioned system generating 5 new users per second, ramped up over 10 seconds, then tear it down:
-
-    `mvn verify -Ptest,teardown -Ddataset=100u -DusersPerSec=5 -DrampUpPeriod=10`
-
-### Cluster
-
-- Provision a 1-node KC cluster + DB, generate data, run test against the provisioned system, then tear it down:
-
-    `mvn verify -Pprovision,cluster,generate-data,test,teardown -Ddataset=100u -DusersPerSec=5`
-
-- Provision a 2-node KC cluster + DB, generate data, run test against the provisioned system, then tear it down:
-
-    `mvn verify -Pprovision,cluster,generate-data,test,teardown -Dkeycloak.scale=2 -DusersPerRealm=200 -DusersPerSec=5`
-
 
 ## Developing tests in IntelliJ IDEA
 
diff --git a/testsuite/performance/tests/docker-compose.sh b/testsuite/performance/tests/docker-compose.sh
index 68529eb..5c79884 100755
--- a/testsuite/performance/tests/docker-compose.sh
+++ b/testsuite/performance/tests/docker-compose.sh
@@ -366,13 +366,16 @@ case "$OPERATION" in
             crossdc) export DB_CONTAINER=${PROJECT_NAME}_mariadb_dc1_1 ;;
             *) echo "Deployment '$DEPLOYMENT' doesn't support operation '$OPERATION'." ; exit 1 ;;
         esac
-        if [ -z "$DATASET" ]; then echo "Operation '$OPERATION' requires DATASET parameter."; exit 1; fi
+        if [ ! -f "$DATASET_PROPERTIES_FILE" ]; then echo "Operation '$OPERATION' requires a valid DATASET_PROPERTIES_FILE parameter."; exit 1; fi
+        DATASET_PROPERTIES_FILENAME=`basename $DATASET_PROPERTIES_FILE`
+        DATASET=${DATASET_PROPERTIES_FILENAME%.properties}
+        echo "DATASET_PROPERTIES_FILE: $DATASET_PROPERTIES_FILE"
         echo "DATASET: $DATASET"
 
         echo "Stopping Keycloak services."
         runCommand "docker-compose -f $DOCKER_COMPOSE_FILE -p ${PROJECT_NAME} stop $KEYCLOAK_SERVICES"
 
-        cd $PROJECT_BASEDIR/datasets
+        cd `dirname $DATASET_PROPERTIES_FILE`
         case "$OPERATION" in
             export-dump)
                 echo "Exporting $DATASET.sql."
@@ -384,7 +387,7 @@ case "$OPERATION" in
             import-dump) 
                 DUMP_DOWNLOAD_SITE=${DUMP_DOWNLOAD_SITE:-https://downloads.jboss.org/keycloak-qe}
                 if [ ! -f "$DATASET.sql.gz" ]; then 
-                    echo "Downloading dump file."
+                    echo "Downloading dump file: $DUMP_DOWNLOAD_SITE/$DATASET.sql.gz"
                     if ! curl -f -O $DUMP_DOWNLOAD_SITE/$DATASET.properties -O $DUMP_DOWNLOAD_SITE/$DATASET.sql.gz ; then
                         echo Download failed.
                         exit 1
@@ -409,6 +412,19 @@ case "$OPERATION" in
 
     ;;
 
+    collect)
+        TIMESTAMP=`date +%s`
+        ARTIFACTS_DIR="${PROJECT_BUILD_DIRECTORY}/collected-artifacts/${DEPLOYMENT}-${TIMESTAMP}"
+        SERVICES=`docker-compose -f $DOCKER_COMPOSE_FILE -p ${PROJECT_NAME} config --services`
+        echo "Collecting docker container logs."
+        rm -rf ${ARTIFACTS_DIR}; mkdir -p ${ARTIFACTS_DIR}
+        for SERVICE in ${SERVICES}; do 
+            docker logs "${PROJECT_NAME}_${SERVICE}_1" > ${ARTIFACTS_DIR}/${SERVICE}.log 2>&1; 
+            if [[ $? != 0 ]]; then echo "ERROR collecting from: ${SERVICE}"; rm ${ARTIFACTS_DIR}/${SERVICE}.log; fi
+        done
+        if [ -z "$(ls -A ${ARTIFACTS_DIR})" ]; then echo "No logs were collected."; rm -rf ${ARTIFACTS_DIR}; fi
+    ;;
+
     *)
         echo "Unsupported operation: '$OPERATION'"
         exit 1
diff --git a/testsuite/performance/tests/parameters/datasets/volume-testing/big.properties b/testsuite/performance/tests/parameters/datasets/volume-testing/big.properties
new file mode 100644
index 0000000..4919199
--- /dev/null
+++ b/testsuite/performance/tests/parameters/datasets/volume-testing/big.properties
@@ -0,0 +1,8 @@
+numOfRealms=200
+usersPerRealm=1000000
+clientsPerRealm=2
+realmRoles=2
+realmRolesPerUser=2
+clientRolesPerUser=2
+clientRolesPerClient=2
+hashIterations=27500
diff --git a/testsuite/performance/tests/parameters/datasets/volume-testing/medium.properties b/testsuite/performance/tests/parameters/datasets/volume-testing/medium.properties
new file mode 100644
index 0000000..b80e841
--- /dev/null
+++ b/testsuite/performance/tests/parameters/datasets/volume-testing/medium.properties
@@ -0,0 +1,8 @@
+numOfRealms=20
+usersPerRealm=10000
+clientsPerRealm=2
+realmRoles=2
+realmRolesPerUser=2
+clientRolesPerUser=2
+clientRolesPerClient=2
+hashIterations=27500
diff --git a/testsuite/performance/tests/parameters/datasets/volume-testing/small.properties b/testsuite/performance/tests/parameters/datasets/volume-testing/small.properties
new file mode 100644
index 0000000..a281f90
--- /dev/null
+++ b/testsuite/performance/tests/parameters/datasets/volume-testing/small.properties
@@ -0,0 +1,8 @@
+numOfRealms=2
+usersPerRealm=1000
+clientsPerRealm=2
+realmRoles=2
+realmRolesPerUser=2
+clientRolesPerUser=2
+clientRolesPerClient=2
+hashIterations=27500
diff --git a/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/cluster.properties b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/cluster.properties
new file mode 100644
index 0000000..d9b1c9d
--- /dev/null
+++ b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/cluster.properties
@@ -0,0 +1,32 @@
+#provisioner=docker-compose
+#deployment=cluster
+
+# Keycloak Settings
+keycloak.scale=1
+keycloak.docker.cpusets=2 3
+keycloak.docker.memlimit=2500m
+keycloak.jvm.memory=-Xms64m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+keycloak.http.max-connections=50000
+keycloak.ajp.max-connections=50000
+keycloak.worker.io-threads=2
+keycloak.worker.task-max-threads=16
+keycloak.ds.min-pool-size=10
+keycloak.ds.max-pool-size=100
+keycloak.ds.pool-prefill=true
+keycloak.ds.ps-cache-size=100
+
+# Database Settings
+db.docker.cpusets=1
+db.docker.memlimit=2g
+db.max.connections=100
+
+# Load Balancer Settings
+lb.docker.cpusets=1
+lb.docker.memlimit=1500m
+lb.jvm.memory=-Xms64m -Xmx1024m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+lb.http.max-connections=50000
+lb.worker.io-threads=2
+lb.worker.task-max-threads=16
+
+# Monitoring Settings
+monitoring.docker.cpusets=0
diff --git a/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/crossdc.properties b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/crossdc.properties
new file mode 100644
index 0000000..4a5083f
--- /dev/null
+++ b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/crossdc.properties
@@ -0,0 +1,42 @@
+#provisioner=docker-compose
+#deployment=crossdc
+
+# Keycloak Settings
+keycloak.dc1.scale=1
+keycloak.dc2.scale=1
+keycloak.dc1.docker.cpusets=2
+keycloak.dc2.docker.cpusets=3
+keycloak.docker.memlimit=2500m
+keycloak.jvm.memory=-Xms64m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+keycloak.http.max-connections=50000
+keycloak.ajp.max-connections=50000
+keycloak.worker.io-threads=2
+keycloak.worker.task-max-threads=16
+keycloak.ds.min-pool-size=10
+keycloak.ds.max-pool-size=100
+keycloak.ds.pool-prefill=true
+keycloak.ds.ps-cache-size=100
+
+# Database Settings
+db.dc1.docker.cpusets=1
+db.dc2.docker.cpusets=1
+db.docker.memlimit=2g
+db.max.connections=100
+
+# Load Balancer Settings
+lb.dc1.docker.cpusets=1
+lb.dc2.docker.cpusets=1
+lb.docker.memlimit=1500m
+lb.jvm.memory=-Xms64m -Xmx1024m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+lb.http.max-connections=50000
+lb.worker.io-threads=2
+lb.worker.task-max-threads=16
+
+# Infinispan Settings
+infinispan.dc1.docker.cpusets=1
+infinispan.dc2.docker.cpusets=1
+infinispan.docker.memlimit=1500m
+infinispan.jvm.memory=-Xms64m -Xmx1g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -XX:+DisableExplicitGC
+        
+# Monitoring Settings
+monitoring.docker.cpusets=0
diff --git a/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/singlenode.properties b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/singlenode.properties
new file mode 100644
index 0000000..e4a52c0
--- /dev/null
+++ b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/singlenode.properties
@@ -0,0 +1,23 @@
+#provisioner=docker-compose
+#deployment=singlenode
+
+# Keycloak Settings
+keycloak.scale=1
+keycloak.docker.cpusets=2-3
+keycloak.docker.memlimit=2500m
+keycloak.jvm.memory=-Xms64m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+keycloak.http.max-connections=50000
+keycloak.worker.io-threads=2
+keycloak.worker.task-max-threads=16
+keycloak.ds.min-pool-size=10
+keycloak.ds.max-pool-size=100
+keycloak.ds.pool-prefill=true
+keycloak.ds.ps-cache-size=100
+
+# Database Settings
+db.docker.cpusets=1
+db.docker.memlimit=2g
+db.max.connections=100
+
+# Monitoring Settings
+monitoring.docker.cpusets=0
diff --git a/testsuite/performance/tests/parameters/test/admin-console.properties b/testsuite/performance/tests/parameters/test/admin-console.properties
new file mode 100644
index 0000000..c3a2773
--- /dev/null
+++ b/testsuite/performance/tests/parameters/test/admin-console.properties
@@ -0,0 +1,8 @@
+gatling.simulationClass=keycloak.AdminConsoleSimulation
+usersPerSec=0.2
+rampUpPeriod=15
+warmUpPeriod=15
+measurementPeriod=30
+filterResults=false
+userThinkTime=0
+refreshTokenPeriod=0
diff --git a/testsuite/performance/tests/parameters/test/basic-oidc.properties b/testsuite/performance/tests/parameters/test/basic-oidc.properties
new file mode 100644
index 0000000..c9a4af0
--- /dev/null
+++ b/testsuite/performance/tests/parameters/test/basic-oidc.properties
@@ -0,0 +1,10 @@
+gatling.simulationClass=keycloak.BasicOIDCSimulation
+usersPerSec=1.0
+rampUpPeriod=15
+warmUpPeriod=15
+measurementPeriod=30
+filterResults=false
+userThinkTime=0
+refreshTokenPeriod=0
+refreshTokenCount=1
+badLoginAttempts=1
diff --git a/testsuite/performance/tests/pom.xml b/testsuite/performance/tests/pom.xml
index 37bb52b..e7c70c5 100644
--- a/testsuite/performance/tests/pom.xml
+++ b/testsuite/performance/tests/pom.xml
@@ -32,56 +32,20 @@
     <properties>
         <provisioner>docker-compose</provisioner>
         <deployment>singlenode</deployment>
-        
-        <provisioned.system.properties.file>${project.build.directory}/provisioned-system.properties</provisioned.system.properties.file>
-
-        <!-- Keycloak Server Settings -->
-        <keycloak.scale/>
-        <keycloak.dc1.scale/>
-        <keycloak.dc2.scale/>
-        <keycloak.docker.cpusets>2-3</keycloak.docker.cpusets>
-        <keycloak.dc1.docker.cpusets>2</keycloak.dc1.docker.cpusets>
-        <keycloak.dc2.docker.cpusets>3</keycloak.dc2.docker.cpusets>
-        <keycloak.docker.memlimit>2500m</keycloak.docker.memlimit>
-        <keycloak.jvm.memory>-Xms64m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</keycloak.jvm.memory>
-        <keycloak.http.max-connections>50000</keycloak.http.max-connections>
-        <keycloak.ajp.max-connections>50000</keycloak.ajp.max-connections>
-        <keycloak.worker.io-threads>2</keycloak.worker.io-threads>
-        <keycloak.worker.task-max-threads>16</keycloak.worker.task-max-threads>
-        <keycloak.ds.min-pool-size>10</keycloak.ds.min-pool-size>
-        <keycloak.ds.max-pool-size>100</keycloak.ds.max-pool-size>
-        <keycloak.ds.pool-prefill>true</keycloak.ds.pool-prefill>
-        <keycloak.ds.ps-cache-size>100</keycloak.ds.ps-cache-size>
-
-        <!-- Database Settings -->
-        <db.docker.cpusets>1</db.docker.cpusets>
-        <db.dc1.docker.cpusets>1</db.dc1.docker.cpusets>
-        <db.dc2.docker.cpusets>1</db.dc2.docker.cpusets>
-        <db.docker.memlimit>2g</db.docker.memlimit>
-        <db.max.connections>100</db.max.connections>
-        <db.dump.download.site>https://downloads.jboss.org/keycloak-qe</db.dump.download.site>
 
-        <!-- Load Balancer Settings -->
-        <lb.docker.cpusets>1</lb.docker.cpusets>
-        <lb.dc1.docker.cpusets>1</lb.dc1.docker.cpusets>
-        <lb.dc2.docker.cpusets>1</lb.dc2.docker.cpusets>
-        <lb.docker.memlimit>1500m</lb.docker.memlimit>
-        <lb.jvm.memory>-Xms64m -Xmx1024m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</lb.jvm.memory>
-        <lb.http.max-connections>50000</lb.http.max-connections>
-        <lb.worker.io-threads>2</lb.worker.io-threads>
-        <lb.worker.task-max-threads>16</lb.worker.task-max-threads>
-
-        <!-- Infinispan Settings -->
-        <infinispan.dc1.docker.cpusets>1</infinispan.dc1.docker.cpusets>
-        <infinispan.dc2.docker.cpusets>1</infinispan.dc2.docker.cpusets>
-        <infinispan.docker.memlimit>1500m</infinispan.docker.memlimit>
-        <infinispan.jvm.memory>-Xms64m -Xmx1g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -XX:+DisableExplicitGC</infinispan.jvm.memory>
+        <provisioning.properties>${provisioner}/4cpus/${deployment}</provisioning.properties>
+        <dataset>2u2c</dataset>
+        <test.properties>basic-oidc</test.properties>
         
-        <!-- Monitoring Settings -->
-        <monitoring.docker.cpusets>0</monitoring.docker.cpusets>
+        <provisioning.properties.file>${project.basedir}/parameters/provisioning/${provisioning.properties}.properties</provisioning.properties.file>
+        <dataset.properties.file>${project.basedir}/parameters/datasets/${dataset}.properties</dataset.properties.file>
+        <test.properties.file>${project.basedir}/parameters/test/${test.properties}.properties</test.properties.file>
+
+        <provisioned.system.properties.file>${project.build.directory}/provisioned-system.properties</provisioned.system.properties.file>
 
-        <!-- Other -->
-        <dataset>default</dataset>
+        <!--other-->
+                        
+        <db.dump.download.site>https://downloads.jboss.org/keycloak-qe/${server.version}</db.dump.download.site>
         <numOfWorkers>1</numOfWorkers>
 
         <maven.compiler.target>1.8</maven.compiler.target>
@@ -207,6 +171,20 @@
                 <version>1.0.0</version>
                 <executions>            
                     <execution>
+                        <id>read-parameters</id>
+                        <phase>initialize</phase>
+                        <goals>
+                            <goal>read-project-properties</goal>
+                        </goals>
+                        <configuration>
+                            <files>
+                                <file>${provisioning.properties.file}</file>
+                                <file>${dataset.properties.file}</file>
+                                <file>${test.properties.file}</file>
+                            </files>
+                        </configuration>
+                    </execution>
+                    <execution>
                         <id>read-existing-provisioned-system-properties</id>
                         <phase>initialize</phase>
                         <goals>
@@ -274,12 +252,11 @@
                     <skip>${gatling.skip.run}</skip>
                     <disableCompiler>true</disableCompiler>
                     <runMultipleSimulations>true</runMultipleSimulations>
-                    <!--includes>
-                        <include>keycloak.DemoSimulation2</include>
-                    </includes-->
                     <jvmArgs>
+                        <!--common params-->
                         <param>-Dproject.build.directory=${project.build.directory}</param>
                         <param>-Dkeycloak.server.uris=${keycloak.frontend.servers}</param>
+                        <!--dataset params-->
                         <param>-DnumOfRealms=${numOfRealms}</param>
                         <param>-DusersPerRealm=${usersPerRealm}</param>
                         <param>-DclientsPerRealm=${clientsPerRealm}</param>
@@ -288,6 +265,16 @@
                         <param>-DclientRolesPerUser=${clientRolesPerUser}</param>
                         <param>-DclientRolesPerClient=${clientRolesPerClient}</param>
                         <param>-DhashIterations=${hashIterations}</param>
+                        <!--test params-->
+                        <param>-DusersPerSec=${usersPerSec}</param>
+                        <param>-DrampUpPeriod=${rampUpPeriod}</param>
+                        <param>-DwarmUpPeriod=${warmUpPeriod}</param>
+                        <param>-DmeasurementPeriod=${measurementPeriod}</param>
+                        <param>-DfilterResults=${filterResults}</param>
+                        <param>-DuserThinkTime=${userThinkTime}</param>
+                        <param>-DrefreshTokenPeriod=${refreshTokenPeriod}</param>
+                        <param>-DrefreshTokenCount=${refreshTokenCount}</param>
+                        <param>-DbadLoginAttempts=${badLoginAttempts}</param>
                     </jvmArgs>
                 </configuration>
 
@@ -314,12 +301,24 @@
     <profiles>
         
         <profile>
-            <id>docker-compose</id>
-            <activation>
-                <property>
-                    <name>!provisioner</name>
-                </property>
-            </activation>
+            <id>cluster</id>
+            <properties>
+                <deployment>cluster</deployment>
+            </properties>
+        </profile>
+        <profile>
+            <id>crossdc</id>
+            <properties>
+                <deployment>crossdc</deployment>
+            </properties>
+        </profile>
+        
+        <profile>
+            <id>provision</id>
+            <properties>
+                <project.basedir>${project.basedir}</project.basedir>
+                <project.build.directory>${project.build.directory}</project.build.directory>
+            </properties>
             <build>
                 <plugins>
                     <plugin>
@@ -327,58 +326,19 @@
                         <artifactId>maven-antrun-plugin</artifactId>
                         <executions>
                             <execution>
-                                <id>copy-dockerfiles-etc</id>
+                                <id>prepare-provisioning</id>
                                 <phase>generate-resources</phase>
                                 <goals>
                                     <goal>run</goal>
                                 </goals>
                                 <configuration>
                                     <target>
-                                        <copy todir="${project.build.directory}/docker-compose" overwrite="false" >
-                                            <fileset dir="${project.basedir}/src/main/docker-compose"/>
-                                        </copy>
-                                        <copy todir="${project.build.directory}/docker-compose" overwrite="false" >
-                                            <fileset dir="${project.basedir}/..">
-                                                <include name="db/**"/>
-                                                <include name="monitoring/**"/>
-                                            </fileset>
-                                        </copy>
-                                        <copy todir="${project.build.directory}/docker-compose/infinispan" overwrite="false" >
-                                            <fileset dir="${project.basedir}/../infinispan/target/docker"/>
-                                        </copy>
-                                        <copy todir="${project.build.directory}/docker-compose/load-balancer/wildfly-modcluster" overwrite="false" >
-                                            <fileset dir="${project.basedir}/../load-balancer/wildfly-modcluster/target/docker"/>
-                                        </copy>
-                                        <copy todir="${project.build.directory}/docker-compose/keycloak" overwrite="false" >
-                                            <fileset dir="${project.basedir}/../keycloak/target/docker"/>
-                                        </copy>
+                                        <ant antfile="prepare-provisioning.xml" target="prepare-${provisioner}" />
                                     </target>
                                 </configuration>
                             </execution>
                         </executions>
                     </plugin>
-                </plugins>
-            </build>
-        </profile>
-        
-        <profile>
-            <id>cluster</id>
-            <properties>
-                <deployment>cluster</deployment>
-                <keycloak.docker.cpusets>2 3</keycloak.docker.cpusets>
-            </properties>
-        </profile>
-        <profile>
-            <id>crossdc</id>
-            <properties>
-                <deployment>crossdc</deployment>
-            </properties>
-        </profile>
-        
-        <profile>
-            <id>provision</id>
-            <build>
-                <plugins>
                     <plugin>
                         <groupId>org.codehaus.mojo</groupId>
                         <artifactId>exec-maven-plugin</artifactId>
@@ -466,39 +426,6 @@
         </profile>
         
         <profile>
-            <id>initialize-dataset-properties</id>
-            <activation>
-                <property>
-                    <name>dataset</name>
-                </property>
-            </activation>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>properties-maven-plugin</artifactId>
-                        <version>1.0.0</version>
-                        <executions>
-                            <execution>
-                                <id>initialize-dataset-properties</id>
-                                <phase>pre-integration-test</phase>
-                                <goals>
-                                    <goal>read-project-properties</goal>
-                                </goals>
-                                <configuration>
-                                    <files>
-                                        <file>${project.basedir}/datasets/${dataset}.properties</file>
-                                    </files>
-                                    <quiet>true</quiet>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>                    
-                </plugins>
-            </build>
-        </profile>
-        
-        <profile>
             <id>generate-data</id>
             <build>
                 <plugins>
@@ -560,26 +487,6 @@
             <build>
                 <plugins>
                     <plugin>
-                        <artifactId>maven-enforcer-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>enforce-nondefault-dataset</id>
-                                <goals>
-                                    <goal>enforce</goal>
-                                </goals>
-                                <configuration>
-                                    <rules>
-                                        <requireProperty>
-                                            <property>dataset</property>
-                                            <regex>(?!default).*</regex>
-                                            <regexMessage>For the "export-dump" task property "dataset" cannot be set to "default".</regexMessage>
-                                        </requireProperty>
-                                    </rules>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
                         <groupId>org.codehaus.mojo</groupId>
                         <artifactId>exec-maven-plugin</artifactId>
                         <executions>
@@ -595,7 +502,7 @@
                                         <PROVISIONER>${provisioner}</PROVISIONER>
                                         <DEPLOYMENT>${deployment}</DEPLOYMENT>
                                         <OPERATION>export-dump</OPERATION>
-                                        <DATASET>${dataset}</DATASET>
+                                        <DATASET_PROPERTIES_FILE>${dataset.properties.file}</DATASET_PROPERTIES_FILE>
                                     </environmentVariables>
                                 </configuration>
                             </execution>
@@ -625,7 +532,7 @@
                                         <PROVISIONER>${provisioner}</PROVISIONER>
                                         <DEPLOYMENT>${deployment}</DEPLOYMENT>
                                         <OPERATION>import-dump</OPERATION>
-                                        <DATASET>${dataset}</DATASET>
+                                        <DATASET_PROPERTIES_FILE>${dataset.properties.file}</DATASET_PROPERTIES_FILE>
                                         <DUMP_DOWNLOAD_SITE>${db.dump.download.site}</DUMP_DOWNLOAD_SITE>
                                     </environmentVariables>
                                 </configuration>
@@ -644,6 +551,35 @@
         </profile>
         
         <profile>
+            <id>collect</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>collect-artifacts</id>
+                                <phase>post-integration-test</phase>
+                                <goals>
+                                    <goal>exec</goal>
+                                </goals>
+                                <configuration>
+                                    <executable>./${provisioner}.sh</executable>
+                                    <environmentVariables>
+                                        <PROVISIONER>${provisioner}</PROVISIONER>
+                                        <DEPLOYMENT>${deployment}</DEPLOYMENT>
+                                        <OPERATION>collect</OPERATION>
+                                    </environmentVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        
+        <profile>
             <id>teardown</id>
             <properties>
                 <delete.data>true</delete.data>
diff --git a/testsuite/performance/tests/prepare-provisioning.xml b/testsuite/performance/tests/prepare-provisioning.xml
new file mode 100644
index 0000000..3108bac
--- /dev/null
+++ b/testsuite/performance/tests/prepare-provisioning.xml
@@ -0,0 +1,24 @@
+<project name="prepare-provisioning" basedir="." >
+
+    <target name="prepare-docker-compose">
+        <copy todir="${project.build.directory}/docker-compose" overwrite="false" >
+            <fileset dir="${project.basedir}/src/main/docker-compose"/>
+        </copy>
+        <copy todir="${project.build.directory}/docker-compose" overwrite="false" failonerror="true">
+            <fileset dir="${project.basedir}/..">
+                <include name="db/**"/>
+                <include name="monitoring/**"/>
+            </fileset>
+        </copy>
+        <copy todir="${project.build.directory}/docker-compose/infinispan" overwrite="false" failonerror="true">
+            <fileset dir="${project.basedir}/../infinispan/target/docker"/>
+        </copy>
+        <copy todir="${project.build.directory}/docker-compose/load-balancer/wildfly-modcluster" overwrite="false" failonerror="true">
+            <fileset dir="${project.basedir}/../load-balancer/wildfly-modcluster/target/docker"/>
+        </copy>
+        <copy todir="${project.build.directory}/docker-compose/keycloak" overwrite="false" failonerror="true">
+            <fileset dir="${project.basedir}/../keycloak/target/docker"/>
+        </copy>
+    </target>
+    
+</project>
diff --git a/testsuite/performance/tests/src/main/java/org/keycloak/performance/TestConfig.java b/testsuite/performance/tests/src/main/java/org/keycloak/performance/TestConfig.java
index 288b067..6d2f194 100644
--- a/testsuite/performance/tests/src/main/java/org/keycloak/performance/TestConfig.java
+++ b/testsuite/performance/tests/src/main/java/org/keycloak/performance/TestConfig.java
@@ -58,9 +58,7 @@ public class TestConfig {
     public static final int rampUpPeriod = Integer.getInteger("rampUpPeriod", 0);
     public static final int warmUpPeriod = Integer.getInteger("warmUpPeriod", 0);
     public static final int measurementPeriod = Integer.getInteger("measurementPeriod", 30);
-    public static final boolean rampDownASAP = Boolean.getBoolean("rampDownASAP"); // check for rampdown condition after each scenario step
     public static final boolean filterResults = Boolean.getBoolean("filterResults"); // filter out results outside of measurementPeriod
-    public static final int pace = Integer.getInteger("pace", 0); // additional dynamic "pause buffer" between scenario loops
     public static final int userThinkTime = Integer.getInteger("userThinkTime", 0);
     public static final int refreshTokenPeriod = Integer.getInteger("refreshTokenPeriod", 0);
 
diff --git a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index dc3bd09..3c1e745 100755
--- a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -25,7 +25,7 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.openqa.selenium.WebDriver;
 
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 1f59ff9..5dbfdc0 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index b4a6d1c..5b1066c 100755
--- a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -26,7 +26,7 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.openqa.selenium.WebDriver;
 
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index 1456496..1324c14 100755
--- a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -26,7 +26,7 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.openqa.selenium.WebDriver;
 
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet>
         <servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsernameServlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
     <servlet-mapping>
         <servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/tomcat-test/webapp/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/tomcat-test/webapp/WEB-INF/web.xml
index 36e0c9e..a4b7254 100755
--- a/testsuite/tomcat8/src/test/resources/tomcat-test/webapp/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/tomcat-test/webapp/WEB-INF/web.xml
@@ -25,7 +25,7 @@
 
     <servlet>
         <servlet-name>SendUsername</servlet-name>
-        <servlet-class>org.keycloak.testsuite.TomcatTest$SendUsernameServlet</servlet-class>
+        <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
     </servlet>
 
     <servlet-mapping>
diff --git a/testsuite/utils/src/main/resources/META-INF/keycloak-server.json b/testsuite/utils/src/main/resources/META-INF/keycloak-server.json
index 12ffb33..eb58977 100755
--- a/testsuite/utils/src/main/resources/META-INF/keycloak-server.json
+++ b/testsuite/utils/src/main/resources/META-INF/keycloak-server.json
@@ -94,7 +94,13 @@
             "l1Lifespan": "${keycloak.connectionsInfinispan.l1Lifespan:600000}",
             "remoteStoreEnabled": "${keycloak.connectionsInfinispan.remoteStoreEnabled:false}",
             "remoteStoreHost": "${keycloak.connectionsInfinispan.remoteStoreServer:localhost}",
-            "remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}"
+            "remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}",
+            "remoteStoreSecurityEnabled": "${keycloak.connectionsInfinispan.remoteStoreSecurityEnabled:false}",
+            "remoteStoreSecurityServerName": "${keycloak.connectionsInfinispan.remoteStoreSecurityServerName:keycloak-server}",
+            "remoteStoreSecurityRealm": "${keycloak.connectionsInfinispan.remoteStoreSecurityRealm:ApplicationRealm}",
+            "remoteStoreSecurityHotRodEndpoint": "${keycloak.connectionsInfinispan.remoteStoreSecurityHotRodEndpoint}",
+            "remoteStoreSecurityUsername": "${keycloak.connectionsInfinispan.remoteStoreSecurityUsername}",
+            "remoteStoreSecurityPassword": "${keycloak.connectionsInfinispan.remoteStoreSecurityPassword}"
         }
     },
 
diff --git a/themes/src/main/resources/theme/base/account/applications.ftl b/themes/src/main/resources/theme/base/account/applications.ftl
index 046df99..0b09256 100755
--- a/themes/src/main/resources/theme/base/account/applications.ftl
+++ b/themes/src/main/resources/theme/base/account/applications.ftl
@@ -28,7 +28,7 @@
                 <tr>
                     <td>
                         <#if application.effectiveUrl?has_content><a href="${application.effectiveUrl}"></#if>
-                            <#if application.client.name??>${advancedMsg(application.client.name)}<#else>${application.client.clientId}</#if>
+                            <#if application.client.name?has_content>${advancedMsg(application.client.name)}<#else>${application.client.clientId}</#if>
                         <#if application.effectiveUrl?has_content></a></#if>
                     </td>
 
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index c384b13..12c5e05 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -309,6 +309,8 @@ user-info-signed-response-alg=User Info Signed Response Algorithm
 user-info-signed-response-alg.tooltip=JWA algorithm used for signed User Info Endpoint response. If set to 'unsigned', then User Info Response won't be signed and will be returned in application/json format.
 request-object-signature-alg=Request Object Signature Algorithm
 request-object-signature-alg.tooltip=JWA algorithm, which client needs to use when sending OIDC request object specified by 'request' or 'request_uri' parameters. If set to 'any', then Request object can be signed by any algorithm (including 'none' ).
+request-object-required=Request Object Required
+request-object-required-alg.tooltip=Specifies if the client needs to provide a request object with their authorization requests, and what method they can use for this. If set to "not required", providing a request object is optional. In all other cases providing a request object is mandatory. If set to "request", the request object must be provided by value. If set to "request_uri", the request object must be provided by reference. If set to "request or request_uri", either method can be used.
 fine-saml-endpoint-conf=Fine Grain SAML Endpoint Configuration
 fine-saml-endpoint-conf.tooltip=Expand this section to configure exact URLs for Assertion Consumer and Single Logout Service.
 assertion-consumer-post-binding-url=Assertion Consumer Service POST Binding URL
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index 632ef2c..381a4c2 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -891,6 +891,13 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
         "none",
         "RS256"
     ];
+    
+    $scope.requestObjectRequiredOptions = [
+        "not required",
+        "request or request_uri",
+        "request only",
+        "request_uri only"
+    ];
 
     $scope.realm = realm;
     $scope.samlAuthnStatement = false;
@@ -1045,6 +1052,9 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
         var attrVal2 = $scope.client.attributes['request.object.signature.alg'];
         $scope.requestObjectSignatureAlg = attrVal2==null ? 'any' : attrVal2;
 
+        var attrVal3 = $scope.client.attributes['request.object.required'];
+        $scope.requestObjectRequired = attrVal3==null ? 'not required' : attrVal3;
+
         if ($scope.client.attributes["exclude.session.state.from.auth.response"]) {
             if ($scope.client.attributes["exclude.session.state.from.auth.response"] == "true") {
                 $scope.excludeSessionStateFromAuthResponse = true;
@@ -1143,6 +1153,14 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
             $scope.clientEdit.attributes['request.object.signature.alg'] = $scope.requestObjectSignatureAlg;
         }
     };
+    
+    $scope.changeRequestObjectRequired = function() {
+        if ($scope.requestObjectRequired === 'not required') {
+            $scope.clientEdit.attributes['request.object.required'] = null;
+        } else {
+            $scope.clientEdit.attributes['request.object.required'] = $scope.requestObjectRequired;
+        }
+    };
 
     $scope.$watch(function() {
         return $location.path();
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
index 96e00e9..9352ff1 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
@@ -409,6 +409,19 @@
                 </div>
                 <kc-tooltip>{{:: 'request-object-signature-alg.tooltip' | translate}}</kc-tooltip>
             </div>
+            <div class="form-group clearfix block" data-ng-show="protocol == 'openid-connect'">
+                <label class="col-md-2 control-label" for="changeRequestObjectRequired">{{:: 'request-object-required' | translate}}</label>
+                <div class="col-sm-6">
+                    <div>
+                        <select class="form-control" id="requestObjectRequired"
+                                ng-change="changeRequestObjectRequired()"
+                                ng-model="requestObjectRequired"
+                                ng-options="sig for sig in requestObjectRequiredOptions">
+                        </select>
+                    </div>
+                </div>
+                <kc-tooltip>{{:: 'request-object-required.tooltip' | translate}}</kc-tooltip>
+            </div>
         </fieldset>
 
         <fieldset data-ng-show="protocol == 'openid-connect'">
diff --git a/themes/src/main/resources-community/theme/base/account/messages/messages_fr.properties b/themes/src/main/resources-community/theme/base/account/messages/messages_fr.properties
index 61c740b..f18bf47 100644
--- a/themes/src/main/resources-community/theme/base/account/messages/messages_fr.properties
+++ b/themes/src/main/resources-community/theme/base/account/messages/messages_fr.properties
@@ -13,7 +13,7 @@ federatedIdentitiesHtmlTitle=Identit\u00e9s f\u00e9d\u00e9r\u00e9es
 accountLogHtmlTitle=Acc\u00e8s au compte
 changePasswordHtmlTitle=Changer de mot de passe
 sessionsHtmlTitle=Sessions
-accountManagementTitle=Gestion de Compte Keycloak
+accountManagementTitle=Gestion du compte Keycloak
 authenticatorTitle=Authentification
 applicationsHtmlTitle=Applications
 
@@ -21,9 +21,9 @@ authenticatorCode=Mot de passe unique
 email=Courriel
 firstName=Pr\u00e9nom
 givenName=Pr\u00e9nom
-fullName=Nom Complet
+fullName=Nom complet
 lastName=Nom
-familyName=Nom de Famille
+familyName=Nom de famille
 password=Mot de passe
 passwordConfirm=Confirmation
 passwordNew=Nouveau mot de passe
@@ -104,17 +104,17 @@ totpStep2=Ouvrez l''application et scannez le code-barres ou entrez la clef.
 totpStep3=Entrez le code \u00e0 usage unique fourni par l''application et cliquez sur Sauvegarder pour terminer.
 
 totpManualStep2=Ouvrez l''application et entrez la clef
-totpManualStep3=Utilisez les valeurs de configuration suivante si l''application les authorise
+totpManualStep3=Utilisez les valeurs de configuration suivante si l''application les autorise
 totpUnableToScan=Impossible de scanner ?
-totpScanBarcode=Scanner le code bare?
+totpScanBarcode=Scanner le code-barres ?
 
 totp.totp=Bas\u00e9 sur le temps
 totp.hotp=Bas\u00e9 sur un compteur
 
 totpType=Type
 totpAlgorithm=Algorithme
-totpDigits=Digits
-totpInterval=Intervale
+totpDigits=Chiffres
+totpInterval=Intervalle
 totpCounter=Compteur
 
 missingUsernameMessage=Veuillez entrer votre nom d''utilisateur.