keycloak-memoizeit

Merge pull request #3179 from pedroigor/KEYCLOAK-3472 [KEYCLOAK-3472]

9/1/2016 10:00:33 AM

Changes

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

testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/photoz-ds.xml 12(+0 -12)

Details

diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
index cfe5ff9..bbbf573 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
@@ -32,6 +32,7 @@ import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathCon
 import org.keycloak.representations.idm.authorization.Permission;
 
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -55,7 +56,7 @@ public abstract class AbstractPolicyEnforcer {
         this.enforcerConfig = policyEnforcer.getEnforcerConfig();
         this.authzClient = policyEnforcer.getClient();
         this.pathMatcher = new PathMatcher();
-        this.paths = policyEnforcer.getPaths();
+        this.paths = new ArrayList<>(policyEnforcer.getPaths());
     }
 
     public AuthorizationContext authorize(OIDCHttpFacade httpFacade) {
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java
index aa6d3d2..88ef9ce 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java
@@ -33,8 +33,12 @@ import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathCon
 import org.keycloak.representations.idm.authorization.Permission;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -95,8 +99,8 @@ public class PolicyEnforcer {
         return authzClient;
     }
 
-    List<PathConfig> getPaths() {
-        return paths;
+    public List<PathConfig> getPaths() {
+        return Collections.unmodifiableList(paths);
     }
 
     KeycloakDeployment getDeployment() {
@@ -154,13 +158,27 @@ public class PolicyEnforcer {
 
                     pathConfig.setId(registrationResponse.getId());
                 } else {
-                    throw new RuntimeException("Could not find matching resource on server with uri [" + path + "] or name [" + resourceName + ". Make sure you have created a resource on the server that matches with the path configuration.");
+                    throw new RuntimeException("Could not find matching resource on server with uri [" + path + "] or name [" + resourceName + "]. Make sure you have created a resource on the server that matches with the path configuration.");
                 }
             } else {
                 pathConfig.setId(search.iterator().next());
             }
 
-            paths.add(pathConfig);
+            PathConfig existingPath = null;
+
+            for (PathConfig current : paths) {
+                if (current.getId().equals(pathConfig.getId()) && current.getPath().equals(pathConfig.getPath())) {
+                    existingPath = current;
+                    break;
+                }
+            }
+
+            if (existingPath == null) {
+                paths.add(pathConfig);
+            } else {
+                existingPath.getMethods().addAll(pathConfig.getMethods());
+                existingPath.getScopes().addAll(pathConfig.getScopes());
+            }
         }
 
         return paths;
diff --git a/examples/authz/photoz/photoz-restful-api/pom.xml b/examples/authz/photoz/photoz-restful-api/pom.xml
index ba7a880..7622af4 100755
--- a/examples/authz/photoz/photoz-restful-api/pom.xml
+++ b/examples/authz/photoz/photoz-restful-api/pom.xml
@@ -40,6 +40,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>javax.enterprise</groupId>
+            <artifactId>cdi-api</artifactId>
+            <version>1.0-SP4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-authz-client</artifactId>
             <version>${project.version}</version>
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
index b349e02..428ba07 100644
--- a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
@@ -19,9 +19,8 @@ package org.keycloak.example.photoz.admin;
 
 import org.keycloak.example.photoz.entity.Album;
 
-import javax.ejb.Stateless;
+import javax.inject.Inject;
 import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
@@ -36,12 +35,11 @@ import java.util.List;
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
 @Path("/admin/album")
-@Stateless
 public class AdminAlbumService {
 
     public static final String SCOPE_ADMIN_ALBUM_MANAGE = "urn:photoz.com:scopes:album:admin:manage";
 
-    @PersistenceContext
+    @Inject
     private EntityManager entityManager;
 
     @Context
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
index a5d7f16..d0e9c2d 100644
--- a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
@@ -7,10 +7,12 @@ 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.ejb.Stateless;
+import javax.inject.Inject;
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
 import javax.persistence.Query;
@@ -31,14 +33,14 @@ import java.util.List;
 import java.util.Set;
 
 @Path("/album")
-@Stateless
+@Transaction
 public class AlbumService {
 
     public static final String SCOPE_ALBUM_VIEW = "urn:photoz.com:scopes:album:view";
     public static final String SCOPE_ALBUM_CREATE = "urn:photoz.com:scopes:album:create";
     public static final String SCOPE_ALBUM_DELETE = "urn:photoz.com:scopes:album:delete";
 
-    @PersistenceContext
+    @Inject
     private EntityManager entityManager;
 
     @Context
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
index be638b6..f7b55cb 100644
--- a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
@@ -18,6 +18,7 @@
 package org.keycloak.example.photoz.album;
 
 import javax.ejb.Stateless;
+import javax.inject.Inject;
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
 import javax.servlet.http.HttpServletRequest;
@@ -34,12 +35,11 @@ import java.util.List;
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
 @Path("/profile")
-@Stateless
 public class ProfileService {
 
     private static final String PROFILE_VIEW = "urn:photoz.com:scopes:profile:view";
 
-    @PersistenceContext
+    @Inject
     private EntityManager entityManager;
 
     @GET
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Resources.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Resources.java
new file mode 100644
index 0000000..c917da2
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Resources.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.util;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Produces;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@ApplicationScoped
+public class Resources {
+
+    private EntityManagerFactory entityManagerFactory;
+
+    @PostConstruct
+    public void init() {
+        entityManagerFactory = Persistence.createEntityManagerFactory("primary");
+    }
+
+    @PreDestroy
+    public void dispose() {
+        entityManagerFactory.close();
+    }
+
+    @RequestScoped
+    @Produces
+    public EntityManager createEntityManager() {
+        return entityManagerFactory.createEntityManager();
+    }
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Transaction.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Transaction.java
new file mode 100644
index 0000000..a3caa78
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Transaction.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.util;
+
+import javax.interceptor.InterceptorBinding;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@InterceptorBinding
+@Target({ TYPE })
+@Retention(RUNTIME)
+public @interface Transaction {
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
new file mode 100644
index 0000000..36d35f3
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.util;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Interceptor
+@Transaction
+public class TransactionInterceptor {
+
+    @Inject
+    private Instance<EntityManager> entityManager;
+
+    @AroundInvoke
+    public Object aroundInvoke(InvocationContext context) {
+        EntityManager entityManager = this.entityManager.get();
+        EntityTransaction transaction = entityManager.getTransaction();
+
+        try {
+            transaction.begin();
+            Object proceed = context.proceed();
+            transaction.commit();
+            return proceed;
+        } catch (Exception cause) {
+            if (transaction != null && transaction.isActive()) {
+                transaction.rollback();
+            }
+            throw new RuntimeException(cause);
+        } finally {
+            entityManager.close();
+        }
+    }
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml b/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
index 957dc8a..fbf2a32 100644
--- a/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
+++ b/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
@@ -3,5 +3,7 @@
    xsi:schemaLocation="
         http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
-        
+    <interceptors>
+        <class>org.keycloak.example.photoz.util.TransactionInterceptor</class>
+    </interceptors>
 </beans>
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml b/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
index 9323182..c15d34f 100644
--- a/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
+++ b/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
@@ -4,14 +4,18 @@
 	xsi:schemaLocation="
         http://java.sun.com/xml/ns/persistence
         http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
-	<persistence-unit name="primary">
-		<non-jta-data-source>java:jboss/datasources/PhotozDS</non-jta-data-source>
+	<persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">
+		<provider>org.hibernate.ejb.HibernatePersistence</provider>
 
 		<class>org.keycloak.example.photoz.entity.Album</class>
 		<class>org.keycloak.example.photoz.entity.Photo</class>
 
 		<properties>
-			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
+			<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
+			<property name="hibernate.connection.driver_class" value="org.h2.Driver" />
+			<property name="hibernate.connection.url" value="jdbc:h2:~/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.show_sql" value="false" />
 		</properties>
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml b/examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
index 4b23be6..4553358 100644
--- a/examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
+++ b/examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
@@ -20,6 +20,7 @@
     <deployment>
         <dependencies>
             <module name="org.keycloak.keycloak-authz-client" services="import"/>
+            <module name="com.h2database.h2" services="import"/>
         </dependencies>
     </deployment>
 </jboss-deployment-structure>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml
index 7885857..f5e2d4c 100755
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml
@@ -40,6 +40,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>javax.enterprise</groupId>
+            <artifactId>cdi-api</artifactId>
+            <version>1.0-SP4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-authz-client</artifactId>
             <version>${project.version}</version>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
index b349e02..428ba07 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
@@ -19,9 +19,8 @@ package org.keycloak.example.photoz.admin;
 
 import org.keycloak.example.photoz.entity.Album;
 
-import javax.ejb.Stateless;
+import javax.inject.Inject;
 import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
@@ -36,12 +35,11 @@ import java.util.List;
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
 @Path("/admin/album")
-@Stateless
 public class AdminAlbumService {
 
     public static final String SCOPE_ADMIN_ALBUM_MANAGE = "urn:photoz.com:scopes:album:admin:manage";
 
-    @PersistenceContext
+    @Inject
     private EntityManager entityManager;
 
     @Context
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 a5d7f16..d0e9c2d 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
@@ -7,10 +7,12 @@ 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.ejb.Stateless;
+import javax.inject.Inject;
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
 import javax.persistence.Query;
@@ -31,14 +33,14 @@ import java.util.List;
 import java.util.Set;
 
 @Path("/album")
-@Stateless
+@Transaction
 public class AlbumService {
 
     public static final String SCOPE_ALBUM_VIEW = "urn:photoz.com:scopes:album:view";
     public static final String SCOPE_ALBUM_CREATE = "urn:photoz.com:scopes:album:create";
     public static final String SCOPE_ALBUM_DELETE = "urn:photoz.com:scopes:album:delete";
 
-    @PersistenceContext
+    @Inject
     private EntityManager entityManager;
 
     @Context
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
index be638b6..f7b55cb 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
@@ -18,6 +18,7 @@
 package org.keycloak.example.photoz.album;
 
 import javax.ejb.Stateless;
+import javax.inject.Inject;
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
 import javax.servlet.http.HttpServletRequest;
@@ -34,12 +35,11 @@ import java.util.List;
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
 @Path("/profile")
-@Stateless
 public class ProfileService {
 
     private static final String PROFILE_VIEW = "urn:photoz.com:scopes:profile:view";
 
-    @PersistenceContext
+    @Inject
     private EntityManager entityManager;
 
     @GET
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Resources.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Resources.java
new file mode 100644
index 0000000..c917da2
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Resources.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.util;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Produces;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@ApplicationScoped
+public class Resources {
+
+    private EntityManagerFactory entityManagerFactory;
+
+    @PostConstruct
+    public void init() {
+        entityManagerFactory = Persistence.createEntityManagerFactory("primary");
+    }
+
+    @PreDestroy
+    public void dispose() {
+        entityManagerFactory.close();
+    }
+
+    @RequestScoped
+    @Produces
+    public EntityManager createEntityManager() {
+        return entityManagerFactory.createEntityManager();
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Transaction.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Transaction.java
new file mode 100644
index 0000000..a3caa78
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Transaction.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.util;
+
+import javax.interceptor.InterceptorBinding;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@InterceptorBinding
+@Target({ TYPE })
+@Retention(RUNTIME)
+public @interface Transaction {
+}
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
new file mode 100644
index 0000000..36d35f3
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.util;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Interceptor
+@Transaction
+public class TransactionInterceptor {
+
+    @Inject
+    private Instance<EntityManager> entityManager;
+
+    @AroundInvoke
+    public Object aroundInvoke(InvocationContext context) {
+        EntityManager entityManager = this.entityManager.get();
+        EntityTransaction transaction = entityManager.getTransaction();
+
+        try {
+            transaction.begin();
+            Object proceed = context.proceed();
+            transaction.commit();
+            return proceed;
+        } catch (Exception cause) {
+            if (transaction != null && transaction.isActive()) {
+                transaction.rollback();
+            }
+            throw new RuntimeException(cause);
+        } finally {
+            entityManager.close();
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
index 957dc8a..fbf2a32 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
@@ -3,5 +3,7 @@
    xsi:schemaLocation="
         http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
-        
+    <interceptors>
+        <class>org.keycloak.example.photoz.util.TransactionInterceptor</class>
+    </interceptors>
 </beans>
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 9323182..8b6d226 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
@@ -4,14 +4,18 @@
 	xsi:schemaLocation="
         http://java.sun.com/xml/ns/persistence
         http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
-	<persistence-unit name="primary">
-		<non-jta-data-source>java:jboss/datasources/PhotozDS</non-jta-data-source>
+	<persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">
+		<provider>org.hibernate.ejb.HibernatePersistence</provider>
 
 		<class>org.keycloak.example.photoz.entity.Album</class>
 		<class>org.keycloak.example.photoz.entity.Photo</class>
 
 		<properties>
-			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
+			<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
+			<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.show_sql" value="false" />
 		</properties>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
index 4b23be6..4553358 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
@@ -20,6 +20,7 @@
     <deployment>
         <dependencies>
             <module name="org.keycloak.keycloak-authz-client" services="import"/>
+            <module name="com.h2database.h2" services="import"/>
         </dependencies>
     </deployment>
 </jboss-deployment-structure>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/EnforcerConfigTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/EnforcerConfigTest.java
new file mode 100644
index 0000000..4236b2e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/EnforcerConfigTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.KeycloakDeploymentBuilder;
+import org.keycloak.adapters.authorization.PolicyEnforcer;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class EnforcerConfigTest extends AbstractKeycloakTest {
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation realm = loadRealm(getClass().getResourceAsStream("/authorization-test/test-authz-realm.json"));
+        testRealms.add(realm);
+    }
+
+    @Test
+    public void testMultiplePathsWithSameName() throws Exception{
+        KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/authorization-test/enforcer-config-paths-same-name.json"));
+        PolicyEnforcer policyEnforcer = deployment.getPolicyEnforcer();
+        List<PolicyEnforcerConfig.PathConfig> paths = policyEnforcer.getPaths();
+        assertEquals(1, paths.size());
+        assertEquals(4, paths.get(0).getMethods().size());
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/enforcer-config-paths-same-name.json b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/enforcer-config-paths-same-name.json
new file mode 100644
index 0000000..19d8c55
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/enforcer-config-paths-same-name.json
@@ -0,0 +1,59 @@
+{
+  "realm": "test-realm-authz",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8180/auth",
+  "ssl-required": "external",
+  "resource": "test-app-authz",
+  "bearer-only": true,
+  "credentials": {
+    "secret": "secret"
+  },
+  "policy-enforcer": {
+    "paths": [
+      {
+        "path": "/v1/product/*",
+        "methods": [
+          {
+            "method": "POST",
+            "scopes": [
+              "create"
+            ]
+          }
+        ]
+      },
+      {
+        "path": "/v1/product/*",
+        "methods": [
+          {
+            "method": "GET",
+            "scopes": [
+              "view"
+            ]
+          }
+        ]
+      },
+      {
+        "path": "/v1/product/*",
+        "methods": [
+          {
+            "method": "PUT",
+            "scopes": [
+              "update"
+            ]
+          }
+        ]
+      },
+      {
+        "path": "/v1/product/*",
+        "methods": [
+          {
+            "method": "DELETE",
+            "scopes": [
+              "delete"
+            ]
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/test-authz-realm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/test-authz-realm.json
new file mode 100644
index 0000000..b1a6f5a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/test-authz-realm.json
@@ -0,0 +1,50 @@
+{
+  "id": "test-realm-authz",
+  "realm": "test-realm-authz",
+  "enabled": true,
+  "sslRequired": "external",
+  "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "requiredCredentials": [ "password" ],
+  "users": [
+    {
+      "username": "service-account-test-app-authz",
+      "enabled": true,
+      "serviceAccountClientId": "test-app-authz",
+      "clientRoles": {
+        "test-app-authz" : ["uma_protection"]
+      }
+    }
+  ],
+  "clients": [
+    {
+      "clientId": "test-app-authz",
+      "enabled": true,
+      "baseUrl": "/test-app-authz",
+      "adminUrl": "/test-app-authz",
+      "bearerOnly": false,
+      "authorizationSettings": {
+        "allowRemoteResourceManagement": true,
+        "policyEnforcementMode": "ENFORCING",
+        "resources": [
+          {
+            "name": "Product Resource",
+            "uri": "/v1/product/*",
+            "scopes": [
+              {
+                "name": "view",
+                "name": "create",
+                "name": "delete",
+                "name": "update"
+              }
+            ]
+          }
+        ]
+      },
+      "redirectUris": [
+        "/test-app-authz/*"
+      ],
+      "secret": "secret"
+    }
+  ]
+}
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index 40e17b5..b2ee848 100755
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -784,6 +784,10 @@
                     <groupId>org.keycloak</groupId>
                     <artifactId>keycloak-saml-adapter-api-public</artifactId>
                 </dependency>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-authz-client</artifactId>
+                </dependency>
 
                 <!--UNDERTOW-->