keycloak-uncached

Changes

Details

diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/group/GroupPolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/group/GroupPolicyProvider.java
index c21b4c0..5f4fcd8 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/group/GroupPolicyProvider.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/group/GroupPolicyProvider.java
@@ -18,9 +18,12 @@ package org.keycloak.authorization.policy.provider.group;
 
 import static org.keycloak.models.utils.ModelToRepresentation.buildGroupPath;
 
+import java.util.List;
 import java.util.function.Function;
 
+import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.attribute.Attributes.Entry;
 import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.policy.evaluation.Evaluation;
 import org.keycloak.authorization.policy.provider.PolicyProvider;
@@ -42,11 +45,13 @@ public class GroupPolicyProvider implements PolicyProvider {
     @Override
     public void evaluate(Evaluation evaluation) {
         GroupPolicyRepresentation policy = representationFunction.apply(evaluation.getPolicy());
-        RealmModel realm = evaluation.getAuthorizationProvider().getRealm();
+        AuthorizationProvider authorizationProvider = evaluation.getAuthorizationProvider();
+        RealmModel realm = authorizationProvider.getRealm();
         Attributes.Entry groupsClaim = evaluation.getContext().getIdentity().getAttributes().getValue(policy.getGroupsClaim());
 
         if (groupsClaim == null || groupsClaim.isEmpty()) {
-            return;
+            List<String> userGroups = evaluation.getRealm().getUserGroups(evaluation.getContext().getIdentity().getId());
+            groupsClaim = new Entry(policy.getGroupsClaim(), userGroups);
         }
 
         for (GroupPolicyRepresentation.GroupDefinition definition : policy.getGroups()) {
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/ScopePolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/ScopePolicyProvider.java
new file mode 100644
index 0000000..3f4f9d9
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/ScopePolicyProvider.java
@@ -0,0 +1,24 @@
+/*
+ * 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.provider.permission;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopePolicyProvider extends AbstractPermissionProvider {
+
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/UMAPolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/UMAPolicyProvider.java
new file mode 100644
index 0000000..50f6993
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/UMAPolicyProvider.java
@@ -0,0 +1,24 @@
+/*
+ * 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.provider.permission;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UMAPolicyProvider extends AbstractPermissionProvider {
+
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/UMAPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/UMAPolicyProviderFactory.java
new file mode 100644
index 0000000..3d11753
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/permission/UMAPolicyProviderFactory.java
@@ -0,0 +1,128 @@
+/*
+ * 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.provider.permission;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UMAPolicyProviderFactory implements PolicyProviderFactory<PolicyRepresentation> {
+
+    private UMAPolicyProvider provider = new UMAPolicyProvider();
+
+    @Override
+    public String getName() {
+        return "UMA";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Others";
+    }
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public PolicyProvider create(AuthorizationProvider authorization) {
+        return provider;
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void onCreate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
+        verifyCircularReference(policy, new ArrayList<>());
+    }
+
+    @Override
+    public void onUpdate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
+        verifyCircularReference(policy, new ArrayList<>());
+    }
+
+    @Override
+    public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
+        verifyCircularReference(policy, new ArrayList<>());
+    }
+
+    @Override
+    public PolicyRepresentation toRepresentation(Policy policy) {
+        return new PolicyRepresentation();
+    }
+
+    @Override
+    public Class<PolicyRepresentation> getRepresentationType() {
+        return PolicyRepresentation.class;
+    }
+
+    private void verifyCircularReference(Policy policy, List<String> ids) {
+        if (!policy.getType().equals("uma")) {
+            return;
+        }
+
+        if (ids.contains(policy.getId())) {
+            throw new RuntimeException("Circular reference found [" + policy.getName() + "].");
+        }
+
+        ids.add(policy.getId());
+
+        for (Policy associated : policy.getAssociatedPolicies()) {
+            verifyCircularReference(associated, ids);
+        }
+    }
+
+    @Override
+    public void onRemove(Policy policy, AuthorizationProvider authorization) {
+
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "uma";
+    }
+}
diff --git a/authz/policy/common/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory b/authz/policy/common/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
index e6fa1cc..2d8c4f3 100644
--- a/authz/policy/common/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
+++ b/authz/policy/common/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
@@ -36,10 +36,11 @@
 
 org.keycloak.authorization.policy.provider.aggregated.AggregatePolicyProviderFactory
 org.keycloak.authorization.policy.provider.js.JSPolicyProviderFactory
-org.keycloak.authorization.policy.provider.resource.ResourcePolicyProviderFactory
+org.keycloak.authorization.policy.provider.permission.ResourcePolicyProviderFactory
 org.keycloak.authorization.policy.provider.role.RolePolicyProviderFactory
-org.keycloak.authorization.policy.provider.scope.ScopePolicyProviderFactory
+org.keycloak.authorization.policy.provider.permission.ScopePolicyProviderFactory
 org.keycloak.authorization.policy.provider.time.TimePolicyProviderFactory
 org.keycloak.authorization.policy.provider.user.UserPolicyProviderFactory
 org.keycloak.authorization.policy.provider.client.ClientPolicyProviderFactory
-org.keycloak.authorization.policy.provider.group.GroupPolicyProviderFactory
\ No newline at end of file
+org.keycloak.authorization.policy.provider.group.GroupPolicyProviderFactory
+org.keycloak.authorization.policy.provider.permission.UMAPolicyProviderFactory
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPermissionTicket.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPermissionTicket.java
index a906a7d..40631b2 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPermissionTicket.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPermissionTicket.java
@@ -18,6 +18,7 @@
 package org.keycloak.models.cache.infinispan.authorization.entities;
 
 import org.keycloak.authorization.model.PermissionTicket;
+import org.keycloak.authorization.model.Policy;
 import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
 
 /**
@@ -33,6 +34,7 @@ public class CachedPermissionTicket extends AbstractRevisioned implements InReso
     private boolean granted;
     private Long createdTimestamp;
     private Long grantedTimestamp;
+    private String policy;
 
     public CachedPermissionTicket(Long revision, PermissionTicket permissionTicket) {
         super(revision, permissionTicket.getId());
@@ -46,6 +48,10 @@ public class CachedPermissionTicket extends AbstractRevisioned implements InReso
         this.granted = permissionTicket.isGranted();
         createdTimestamp = permissionTicket.getCreatedTimestamp();
         grantedTimestamp = permissionTicket.getGrantedTimestamp();
+        Policy policy = permissionTicket.getPolicy();
+        if (policy != null) {
+            this.policy = policy.getId();
+        }
     }
 
     public String getOwner() {
@@ -80,4 +86,7 @@ public class CachedPermissionTicket extends AbstractRevisioned implements InReso
         return this.resourceServerId;
     }
 
+    public String getPolicy() {
+        return policy;
+    }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPolicy.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPolicy.java
index 11d6e64..643c868 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPolicy.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPolicy.java
@@ -45,6 +45,7 @@ public class CachedPolicy extends AbstractRevisioned implements InResourceServer
     private Set<String> associatedPoliciesIds;
     private Set<String> resourcesIds;
     private Set<String> scopesIds;
+    private final String owner;
 
     public CachedPolicy(Long revision, Policy policy) {
         super(revision, policy.getId());
@@ -58,6 +59,7 @@ public class CachedPolicy extends AbstractRevisioned implements InResourceServer
         this.associatedPoliciesIds = policy.getAssociatedPolicies().stream().map(Policy::getId).collect(Collectors.toSet());
         this.resourcesIds = policy.getResources().stream().map(Resource::getId).collect(Collectors.toSet());
         this.scopesIds = policy.getScopes().stream().map(Scope::getId).collect(Collectors.toSet());
+        this.owner = policy.getOwner();
     }
 
     public String getType() {
@@ -100,4 +102,7 @@ public class CachedPolicy extends AbstractRevisioned implements InResourceServer
         return this.resourceServerId;
     }
 
+    public String getOwner() {
+        return owner;
+    }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketRemovedEvent.java
index bbef979..f5296e6 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketRemovedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketRemovedEvent.java
@@ -32,11 +32,13 @@ public class PermissionTicketRemovedEvent extends InvalidationEvent implements A
     private String resource;
     private String scope;
     private String serverId;
+    private String requester;
 
-    public static PermissionTicketRemovedEvent create(String id, String owner, String resource, String scope, String serverId) {
+    public static PermissionTicketRemovedEvent create(String id, String owner, String requester, String resource, String scope, String serverId) {
         PermissionTicketRemovedEvent event = new PermissionTicketRemovedEvent();
         event.id = id;
         event.owner = owner;
+        event.requester = requester;
         event.resource = resource;
         event.scope = scope;
         event.serverId = serverId;
@@ -55,6 +57,6 @@ public class PermissionTicketRemovedEvent extends InvalidationEvent implements A
 
     @Override
     public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
-        cache.permissionTicketRemoval(id, owner, resource, scope, serverId, invalidations);
+        cache.permissionTicketRemoval(id, owner, requester, resource, scope, serverId, invalidations);
     }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketUpdatedEvent.java
index 1d830ed..3323531 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketUpdatedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketUpdatedEvent.java
@@ -32,11 +32,13 @@ public class PermissionTicketUpdatedEvent extends InvalidationEvent implements A
     private String resource;
     private String scope;
     private String serverId;
+    private String requester;
 
-    public static PermissionTicketUpdatedEvent create(String id, String owner, String resource, String scope, String serverId) {
+    public static PermissionTicketUpdatedEvent create(String id, String owner, String requester, String resource, String scope, String serverId) {
         PermissionTicketUpdatedEvent event = new PermissionTicketUpdatedEvent();
         event.id = id;
         event.owner = owner;
+        event.requester = requester;
         event.resource = resource;
         event.scope = scope;
         event.serverId = serverId;
@@ -55,6 +57,6 @@ public class PermissionTicketUpdatedEvent extends InvalidationEvent implements A
 
     @Override
     public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
-        cache.permissionTicketUpdated(id, owner, resource, scope, serverId, invalidations);
+        cache.permissionTicketUpdated(id, owner, requester, resource, scope, serverId, invalidations);
     }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PermissionTicketAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PermissionTicketAdapter.java
index d6a7e07..3ef19cf 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PermissionTicketAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PermissionTicketAdapter.java
@@ -18,6 +18,7 @@ package org.keycloak.models.cache.infinispan.authorization;
 
 import org.keycloak.authorization.model.CachedModel;
 import org.keycloak.authorization.model.PermissionTicket;
+import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.model.Resource;
 import org.keycloak.authorization.model.ResourceServer;
 import org.keycloak.authorization.model.Scope;
@@ -41,7 +42,7 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
     @Override
     public PermissionTicket getDelegateForUpdate() {
         if (updated == null) {
-            cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getResourceId(), cached.getScopeId(), cached.getResourceServerId());
+            cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), cached.getScopeId(), cached.getResourceServerId());
             updated = cacheSession.getPermissionTicketStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
             if (updated == null) throw new IllegalStateException("Not found in database");
         }
@@ -113,7 +114,7 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
     @Override
     public void setGrantedTimestamp(Long millis) {
         getDelegateForUpdate();
-        cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getResourceId(), cached.getScopeId(), cached.getResourceServerId());
+        cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), cached.getScopeId(), cached.getResourceServerId());
         updated.setGrantedTimestamp(millis);
     }
 
@@ -123,6 +124,19 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
     }
 
     @Override
+    public Policy getPolicy() {
+        if (isUpdated()) return updated.getPolicy();
+        return cacheSession.getPolicyStore().findById(cached.getPolicy(), cached.getResourceServerId());
+    }
+
+    @Override
+    public void setPolicy(Policy policy) {
+        getDelegateForUpdate();
+        cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), cached.getScopeId(), cached.getResourceServerId());
+        updated.setPolicy(policy);
+    }
+
+    @Override
     public Resource getResource() {
         return cacheSession.getResourceStore().findById(cached.getResourceId(), getResourceServer().getId());
     }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
index c75ffa4..4b34cf9 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
@@ -100,7 +100,6 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
         getDelegateForUpdate();
         cacheSession.registerPolicyInvalidation(cached.getId(), name, cached.getResourcesIds(), cached.getScopesIds(), cached.getConfig().get("defaultResourceType"), cached.getResourceServerId());
         updated.setName(name);
-
     }
 
     @Override
@@ -279,6 +278,19 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
     }
 
     @Override
+    public String getOwner() {
+        if (isUpdated()) return updated.getOwner();
+        return cached.getOwner();
+    }
+
+    @Override
+    public void setOwner(String owner) {
+        getDelegateForUpdate();
+        cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourcesIds(), cached.getScopesIds(), cached.getConfig().get("defaultResourceType"), cached.getResourceServerId());
+        updated.setOwner(owner);
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || !(o instanceof Policy)) return false;
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
index 4f59cdb..e6ec3d8 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
@@ -199,7 +199,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
 
         for (Scope scope : updated.getScopes()) {
             if (!scopes.contains(scope)) {
-                PermissionTicketStore permissionStore = cacheSession.getPermissionTicketStoreDelegate();
+                PermissionTicketStore permissionStore = cacheSession.getPermissionTicketStore();
                 List<PermissionTicket> permissions = permissionStore.findByScope(scope.getId(), getResourceServer().getId());
 
                 for (PermissionTicket permission : permissions) {
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 e54316d..c3a1424 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
@@ -135,10 +135,11 @@ public class StoreFactoryCacheManager extends CacheManager {
         }
     }
 
-    public void permissionTicketUpdated(String id, String owner, String resource, String scope, String serverId, Set<String> invalidations) {
+    public void permissionTicketUpdated(String id, String owner, String requester, String resource, String scope, String serverId, Set<String> invalidations) {
         invalidations.add(id);
         invalidations.add(StoreFactoryCacheSession.getPermissionTicketByOwner(owner, serverId));
         invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(resource, serverId));
+        invalidations.add(StoreFactoryCacheSession.getPermissionTicketByGranted(requester, serverId));
         if (scope != null) {
             invalidations.add(StoreFactoryCacheSession.getPermissionTicketByScope(scope, serverId));
         }
@@ -148,8 +149,8 @@ public class StoreFactoryCacheManager extends CacheManager {
         policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations);
     }
 
-    public void permissionTicketRemoval(String id, String owner, String resource, String scope, String serverId, Set<String> invalidations) {
-        permissionTicketUpdated(id, owner, resource, scope, serverId, invalidations);
+    public void permissionTicketRemoval(String id, String owner, String requester, String resource, String scope, String serverId, Set<String> invalidations) {
+        permissionTicketUpdated(id, owner, requester, resource, scope, serverId, invalidations);
     }
 
 }
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 5924573..b08629a 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
@@ -30,6 +30,7 @@ import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import org.jboss.logging.Logger;
+import org.keycloak.authorization.UserManagedPermissionUtil;
 import org.keycloak.authorization.model.PermissionTicket;
 import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.model.Resource;
@@ -283,12 +284,12 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         invalidationEvents.add(PolicyUpdatedEvent.create(id, name, resources, resourceTypes, scopes, serverId));
     }
 
-    public void registerPermissionTicketInvalidation(String id, String owner, String resource,  String scope,  String serverId) {
-        cache.permissionTicketUpdated(id, owner, resource, scope, serverId, invalidations);
+    public void registerPermissionTicketInvalidation(String id, String owner, String requester, String resource,  String scope,  String serverId) {
+        cache.permissionTicketUpdated(id, owner, requester, resource, scope, serverId, invalidations);
         PermissionTicketAdapter adapter = managedPermissionTickets.get(id);
         if (adapter != null) adapter.invalidateFlag();
 
-        invalidationEvents.add(PermissionTicketUpdatedEvent.create(id, owner, resource, scope, serverId));
+        invalidationEvents.add(PermissionTicketUpdatedEvent.create(id, owner, requester, resource, scope, serverId));
     }
 
     private Set<String> getResourceTypes(Set<String> resources, String serverId) {
@@ -384,6 +385,10 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         return "permission.ticket.scope." + scopeId + "." + serverId;
     }
 
+    public static String getPermissionTicketByGranted(String userId, String serverId) {
+        return "permission.ticket.granted." + userId + "." + serverId;
+    }
+
     public static String getPermissionTicketByOwner(String owner, String serverId) {
         return "permission.ticket.owner." + owner + "." + serverId;
     }
@@ -836,7 +841,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         @Override
         public PermissionTicket create(String resourceId, String scopeId, String requester, ResourceServer resourceServer) {
             PermissionTicket created = getPermissionTicketStoreDelegate().create(resourceId, scopeId, requester, resourceServer);
-            registerPermissionTicketInvalidation(created.getId(), created.getOwner(), created.getResource().getId(), scopeId, created.getResourceServer().getId());
+            registerPermissionTicketInvalidation(created.getId(), created.getOwner(), created.getRequester(), created.getResource().getId(), scopeId, created.getResourceServer().getId());
             return created;
         }
 
@@ -851,9 +856,10 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             if (permission.getScope() != null) {
                 scopeId = permission.getScope().getId();
             }
-            invalidationEvents.add(PermissionTicketRemovedEvent.create(id, permission.getOwner(), permission.getResource().getId(), scopeId, permission.getResourceServer().getId()));
-            cache.permissionTicketRemoval(id, permission.getOwner(), permission.getResource().getId(), scopeId, permission.getResourceServer().getId(), invalidations);
+            invalidationEvents.add(PermissionTicketRemovedEvent.create(id, permission.getOwner(), permission.getRequester(), permission.getResource().getId(), scopeId, permission.getResourceServer().getId()));
+            cache.permissionTicketRemoval(id, permission.getOwner(), permission.getRequester(), permission.getResource().getId(), scopeId, permission.getResourceServer().getId(), invalidations);
             getPermissionTicketStoreDelegate().delete(id);
+            UserManagedPermissionUtil.removePolicy(permission, StoreFactoryCacheSession.this);
 
         }
 
@@ -909,6 +915,13 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         }
 
         @Override
+        public List<PermissionTicket> findGranted(String userId, String resourceServerId) {
+            String cacheKey = getPermissionTicketByGranted(userId, resourceServerId);
+            return cacheQuery(cacheKey, PermissionTicketListQuery.class, () -> getPermissionTicketStoreDelegate().findGranted(userId, resourceServerId),
+                    (revision, permissions) -> new PermissionTicketListQuery(revision, cacheKey, permissions.stream().map(permission -> permission.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
+        }
+
+        @Override
         public List<PermissionTicket> findByOwner(String owner, String resourceServerId) {
             String cacheKey = getPermissionTicketByOwner(owner, resourceServerId);
             return cacheQuery(cacheKey, PermissionTicketListQuery.class, () -> getPermissionTicketStoreDelegate().findByOwner(owner, resourceServerId),
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PermissionTicketEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PermissionTicketEntity.java
index 1cd8d07..4bf334c 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PermissionTicketEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PermissionTicketEntity.java
@@ -76,6 +76,10 @@ public class PermissionTicketEntity {
     @JoinColumn(name = "RESOURCE_SERVER_ID")
     private ResourceServerEntity resourceServer;
 
+    @ManyToOne(optional = true, fetch = FetchType.LAZY)
+    @JoinColumn(name = "POLICY_ID")
+    private PolicyEntity policy;
+
     public String getId() {
         return id;
     }
@@ -144,6 +148,14 @@ public class PermissionTicketEntity {
         return grantedTimestamp != null;
     }
 
+    public PolicyEntity getPolicy() {
+        return policy;
+    }
+
+    public void setPolicy(PolicyEntity policy) {
+        this.policy = policy;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
index 984c6ba..e235f58 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
@@ -113,6 +113,9 @@ public class PolicyEntity {
     @JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
     private Set<ScopeEntity> scopes = new HashSet<>();
 
+    @Column(name = "OWNER")
+    private String owner;
+
     public String getId() {
         return this.id;
     }
@@ -201,6 +204,14 @@ public class PolicyEntity {
         this.associatedPolicies = associatedPolicies;
     }
 
+    public String getOwner() {
+        return owner;
+    }
+
+    public void setOwner(String owner) {
+        this.owner = owner;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
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 8c9960b..8b1d903 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
@@ -56,7 +56,7 @@ import org.hibernate.annotations.FetchMode;
                 @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.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="findResourceIdByType", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId  and r.owner = :ownerId 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))"),
                 @NamedQuery(name="deleteResourceByResourceServer", query="delete from ResourceEntity r where r.resourceServer.id = :serverId")
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPermissionTicketStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPermissionTicketStore.java
index ee51d5e..3ab4da9 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPermissionTicketStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPermissionTicketStore.java
@@ -18,9 +18,11 @@ package org.keycloak.authorization.jpa.store;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import javax.persistence.EntityManager;
 import javax.persistence.FlushModeType;
@@ -102,9 +104,15 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
 
         List<String> result = query.getResultList();
         List<PermissionTicket> list = new LinkedList<>();
+        PermissionTicketStore ticketStore = provider.getStoreFactory().getPermissionTicketStore();
+
         for (String id : result) {
-            list.add(provider.getStoreFactory().getPermissionTicketStore().findById(id, resourceServerId));
+            PermissionTicket ticket = ticketStore.findById(id, resourceServerId);
+            if (Objects.nonNull(ticket)) {
+                list.add(ticket);
+            }
         }
+
         return list;
     }
 
@@ -118,9 +126,15 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
 
         List<String> result = query.getResultList();
         List<PermissionTicket> list = new LinkedList<>();
+        PermissionTicketStore ticketStore = provider.getStoreFactory().getPermissionTicketStore();
+
         for (String id : result) {
-            list.add(provider.getStoreFactory().getPermissionTicketStore().findById(id, resourceServerId));
+            PermissionTicket ticket = ticketStore.findById(id, resourceServerId);
+            if (Objects.nonNull(ticket)) {
+                list.add(ticket);
+            }
         }
+
         return list;
     }
 
@@ -139,9 +153,15 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
 
         List<String> result = query.getResultList();
         List<PermissionTicket> list = new LinkedList<>();
+        PermissionTicketStore ticketStore = provider.getStoreFactory().getPermissionTicketStore();
+
         for (String id : result) {
-            list.add(provider.getStoreFactory().getPermissionTicketStore().findById(id, resourceServerId));
+            PermissionTicket ticket = ticketStore.findById(id, resourceServerId);
+            if (Objects.nonNull(ticket)) {
+                list.add(ticket);
+            }
         }
+
         return list;
     }
 
@@ -184,6 +204,8 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
                 }
             } else if (PermissionTicket.REQUESTER_IS_NULL.equals(name)) {
                 predicates.add(builder.isNull(root.get("requester")));
+            } else if (PermissionTicket.POLICY_IS_NOT_NULL.equals(name)) {
+                predicates.add(builder.isNotNull(root.get("policy")));
             } else {
                 throw new RuntimeException("Unsupported filter [" + name + "]");
             }
@@ -196,22 +218,36 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
         if (firstResult != -1) {
             query.setFirstResult(firstResult);
         }
+
         if (maxResult != -1) {
             query.setMaxResults(maxResult);
         }
 
         List<String> result = query.getResultList();
         List<PermissionTicket> list = new LinkedList<>();
-        PermissionTicketStore ticket = provider.getStoreFactory().getPermissionTicketStore();
+        PermissionTicketStore ticketStore = provider.getStoreFactory().getPermissionTicketStore();
 
         for (String id : result) {
-            list.add(ticket.findById(id, resourceServerId));
+            PermissionTicket ticket = ticketStore.findById(id, resourceServerId);
+            if (Objects.nonNull(ticket)) {
+                list.add(ticket);
+            }
         }
 
         return list;
     }
 
     @Override
+    public List<PermissionTicket> findGranted(String userId, String resourceServerId) {
+        HashMap<String, String> filters = new HashMap<>();
+
+        filters.put(PermissionTicket.GRANTED, Boolean.TRUE.toString());
+        filters.put(PermissionTicket.REQUESTER, userId);
+
+        return find(filters, resourceServerId, -1, -1);
+    }
+
+    @Override
     public List<PermissionTicket> findByOwner(String owner, String resourceServerId) {
         TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByType", String.class);
 
@@ -221,9 +257,15 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
 
         List<String> result = query.getResultList();
         List<PermissionTicket> list = new LinkedList<>();
+        PermissionTicketStore ticketStore = provider.getStoreFactory().getPermissionTicketStore();
+
         for (String id : result) {
-            list.add(provider.getStoreFactory().getPermissionTicketStore().findById(id, resourceServerId));
+            PermissionTicket ticket = ticketStore.findById(id, resourceServerId);
+            if (Objects.nonNull(ticket)) {
+                list.add(ticket);
+            }
         }
+
         return list;
     }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
index 139973c..021f451 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
@@ -142,11 +142,21 @@ public class JPAPolicyStore implements PolicyStore {
                 }
             } else if ("id".equals(name)) {
                 predicates.add(root.get(name).in(value));
+            } else if ("owner".equals(name)) {
+                predicates.add(root.get(name).in(value));
+            } else if ("owner_is_not_null".equals(name)) {
+                predicates.add(builder.isNotNull(root.get("owner")));
+            } else if ("resource".equals(name)) {
+                predicates.add(root.join("resources").get("id").in(value));
             } else {
                 predicates.add(builder.like(builder.lower(root.get(name)), "%" + value[0].toLowerCase() + "%"));
             }
         });
 
+        if (!attributes.containsKey("owner") && !attributes.containsKey("owner_is_not_null")) {
+            predicates.add(builder.isNull(root.get("owner")));
+        }
+
         querybuilder.where(predicates.toArray(new Predicate[predicates.size()])).orderBy(builder.asc(root.get("name")));
 
         Query query = entityManager.createQuery(querybuilder);
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 b9cecf7..7f6338d 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
@@ -267,6 +267,7 @@ public class JPAResourceStore implements ResourceStore {
 
         query.setFlushMode(FlushModeType.COMMIT);
         query.setParameter("type", type);
+        query.setParameter("ownerId", resourceServerId);
         query.setParameter("serverId", resourceServerId);
 
         List<String> result = query.getResultList();
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PermissionTicketAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PermissionTicketAdapter.java
index e1c56a2..6f66a2e 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PermissionTicketAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PermissionTicketAdapter.java
@@ -16,9 +16,12 @@
  */
 package org.keycloak.authorization.jpa.store;
 
+import static org.keycloak.authorization.UserManagedPermissionUtil.updatePolicy;
+
 import javax.persistence.EntityManager;
 
 import org.keycloak.authorization.jpa.entities.PermissionTicketEntity;
+import org.keycloak.authorization.jpa.entities.PolicyEntity;
 import org.keycloak.authorization.jpa.entities.ScopeEntity;
 import org.keycloak.authorization.model.PermissionTicket;
 import org.keycloak.authorization.model.Policy;
@@ -34,13 +37,13 @@ import org.keycloak.models.jpa.JpaModel;
  */
 public class PermissionTicketAdapter implements PermissionTicket, JpaModel<PermissionTicketEntity> {
 
-    private PermissionTicketEntity entity;
-    private EntityManager em;
-    private StoreFactory storeFactory;
+    private final EntityManager entityManager;
+    private final PermissionTicketEntity entity;
+    private final StoreFactory storeFactory;
 
-    public PermissionTicketAdapter(PermissionTicketEntity entity, EntityManager em, StoreFactory storeFactory) {
+    public PermissionTicketAdapter(PermissionTicketEntity entity, EntityManager entityManager, StoreFactory storeFactory) {
         this.entity = entity;
-        this.em = em;
+        this.entityManager = entityManager;
         this.storeFactory = storeFactory;
     }
 
@@ -82,6 +85,7 @@ public class PermissionTicketAdapter implements PermissionTicket, JpaModel<Permi
     @Override
     public void setGrantedTimestamp(Long millis) {
         entity.setGrantedTimestamp(millis);
+        updatePolicy(this, storeFactory);
     }
 
     @Override
@@ -90,6 +94,24 @@ public class PermissionTicketAdapter implements PermissionTicket, JpaModel<Permi
     }
 
     @Override
+    public Policy getPolicy() {
+        PolicyEntity policy = entity.getPolicy();
+
+        if (policy == null) {
+            return null;
+        }
+
+        return storeFactory.getPolicyStore().findById(policy.getId(), entity.getResourceServer().getId());
+    }
+
+    @Override
+    public void setPolicy(Policy policy) {
+        if (policy != null) {
+            entity.setPolicy(entityManager.getReference(PolicyEntity.class, policy.getId()));
+        }
+    }
+
+    @Override
     public Resource getResource() {
         return storeFactory.getResourceStore().findById(entity.getResource().getId(), getResourceServer().getId());
     }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java
index b789165..98651da 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java
@@ -208,6 +208,16 @@ public class PolicyAdapter implements Policy, JpaModel<PolicyEntity> {
     }
 
     @Override
+    public void setOwner(String owner) {
+        entity.setOwner(owner);
+    }
+
+    @Override
+    public String getOwner() {
+        return entity.getOwner();
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || !(o instanceof Policy)) return false;
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-authz-4.0.0.Beta3.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-authz-4.0.0.Beta3.xml
new file mode 100755
index 0000000..e5073da
--- /dev/null
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-authz-4.0.0.Beta3.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ * 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.
+  -->
+
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd">
+    <changeSet author="psilva@redhat.com" id="authz-4.0.0.Beta3">
+        <addColumn tableName="RESOURCE_SERVER_POLICY">
+            <column name="OWNER" type="VARCHAR(36)">
+                <constraints nullable="true"/>
+            </column>
+        </addColumn>
+        <addColumn tableName="RESOURCE_SERVER_PERM_TICKET">
+            <column name="POLICY_ID" type="VARCHAR(36)">
+                <constraints nullable="true"/>
+            </column>
+        </addColumn>
+        <addForeignKeyConstraint baseColumnNames="POLICY_ID" baseTableName="RESOURCE_SERVER_PERM_TICKET" constraintName="FK_FRSRPO2128CX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_POLICY"/>
+    </changeSet>
+</databaseChangeLog>
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
index c9d0e16..554df64 100755
--- a/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
@@ -55,4 +55,5 @@
     <include file="META-INF/jpa-changelog-3.4.2.xml"/>
     <include file="META-INF/jpa-changelog-4.0.0.xml"/>
     <include file="META-INF/jpa-changelog-authz-4.0.0.CR1.xml"/>
+    <include file="META-INF/jpa-changelog-authz-4.0.0.Beta3.xml"/>
 </databaseChangeLog>
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 88c898b..57f4c93 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
@@ -235,7 +235,7 @@ public final class AuthorizationProvider implements Provider {
             @Override
             public void delete(String id) {
                 Scope scope = findById(id, null);
-                PermissionTicketStore ticketStore = storeFactory.getPermissionTicketStore();
+                PermissionTicketStore ticketStore = AuthorizationProvider.this.getStoreFactory().getPermissionTicketStore();
                 List<PermissionTicket> permissions = ticketStore.findByScope(id, scope.getResourceServer().getId());
 
                 for (PermissionTicket permission : permissions) {
@@ -414,6 +414,7 @@ public final class AuthorizationProvider implements Provider {
             @Override
             public void delete(String id) {
                 Resource resource = findById(id, null);
+                StoreFactory storeFactory = AuthorizationProvider.this.getStoreFactory();
                 PermissionTicketStore ticketStore = storeFactory.getPermissionTicketStore();
                 List<PermissionTicket> permissions = ticketStore.findByResource(id, resource.getResourceServer().getId());
 
@@ -421,6 +422,17 @@ public final class AuthorizationProvider implements Provider {
                     ticketStore.delete(permission.getId());
                 }
 
+                PolicyStore policyStore = storeFactory.getPolicyStore();
+                List<Policy> policies = policyStore.findByResource(id, resource.getResourceServer().getId());
+
+                for (Policy policyModel : policies) {
+                    if (policyModel.getResources().size() == 1) {
+                        policyStore.delete(policyModel.getId());
+                    } else {
+                        policyModel.removeResource(resource);
+                    }
+                }
+
                 delegate.delete(id);
             }
 
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/model/PermissionTicket.java b/server-spi-private/src/main/java/org/keycloak/authorization/model/PermissionTicket.java
index 39366d6..493bfc2 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/model/PermissionTicket.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/model/PermissionTicket.java
@@ -29,6 +29,7 @@ public interface PermissionTicket {
     String GRANTED = "granted";
     String REQUESTER = "requester";
     String REQUESTER_IS_NULL = "requester_is_null";
+    String POLICY_IS_NOT_NULL = "policy_is_not_null";
 
     /**
      * Returns the unique identifier for this instance.
@@ -73,4 +74,8 @@ public interface PermissionTicket {
      * @return a resource server
      */
     ResourceServer getResourceServer();
+
+    Policy getPolicy();
+
+    void setPolicy(Policy policy);
 }
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java b/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
index f46f61a..0dafea9 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
@@ -148,6 +148,10 @@ public interface Policy {
      */
     Set<Scope> getScopes();
 
+    String getOwner();
+
+    void setOwner(String owner);
+
     void addScope(Scope scope);
 
     void removeScope(Scope scope);
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 cbf23cb..e92dbba 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
@@ -48,12 +48,21 @@ public class DefaultEvaluation implements Evaluation {
     private final ResourcePermission permission;
     private final EvaluationContext executionContext;
     private final Decision decision;
-    private final Policy policy;
+    private 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, Decision decision, AuthorizationProvider authorizationProvider) {
+        this.permission = permission;
+        this.executionContext = executionContext;
+        this.parentPolicy = parentPolicy;
+        this.decision = decision;
+        this.authorizationProvider = authorizationProvider;
+        this.realm = createRealm();
+    }
+
     public DefaultEvaluation(ResourcePermission permission, EvaluationContext executionContext, Policy parentPolicy, Policy policy, Decision decision, AuthorizationProvider authorizationProvider) {
         this.permission = permission;
         this.executionContext = executionContext;
@@ -98,6 +107,9 @@ public class DefaultEvaluation implements Evaluation {
 
     @Override
     public Policy getPolicy() {
+        if (policy == null) {
+            return parentPolicy;
+        }
         return this.policy;
     }
 
@@ -119,7 +131,8 @@ public class DefaultEvaluation implements Evaluation {
         return effect;
     }
 
-    void denyIfNoEffect() {
+    @Override
+    public void denyIfNoEffect() {
         if (this.effect == null) {
             deny();
         }
@@ -248,4 +261,8 @@ public class DefaultEvaluation implements Evaluation {
             }
         };
     }
+
+    public void setPolicy(Policy policy) {
+        this.policy = policy;
+    }
 }
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultPolicyEvaluator.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultPolicyEvaluator.java
index 0cc0622..24127d6 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultPolicyEvaluator.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultPolicyEvaluator.java
@@ -63,7 +63,7 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
         PolicyEnforcementMode enforcementMode = resourceServer.getPolicyEnforcementMode();
 
         if (PolicyEnforcementMode.DISABLED.equals(enforcementMode)) {
-            createEvaluation(permission, executionContext, decision, null, null).grant();
+            createEvaluation(permission, executionContext, decision, null).grant();
             return;
         }
 
@@ -95,7 +95,7 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
         }
 
         if (PolicyEnforcementMode.PERMISSIVE.equals(enforcementMode) && !verified.get()) {
-            createEvaluation(permission, executionContext, decision, null, null).grant();
+            createEvaluation(permission, executionContext, decision, null).grant();
         }
     }
 
@@ -113,25 +113,22 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
                 return;
             }
 
-            for (Policy associatedPolicy : parentPolicy.getAssociatedPolicies()) {
-                PolicyProvider policyProvider = authorization.getProvider(associatedPolicy.getType());
+            PolicyProvider policyProvider = authorization.getProvider(parentPolicy.getType());
 
-                if (policyProvider == null) {
-                    throw new RuntimeException("Unknown parentPolicy provider for type [" + associatedPolicy.getType() + "].");
-                }
+            if (policyProvider == null) {
+                throw new RuntimeException("Unknown parentPolicy provider for type [" + parentPolicy.getType() + "].");
+            }
 
-                DefaultEvaluation evaluation = createEvaluation(permission, executionContext, decision, parentPolicy, associatedPolicy);
+            DefaultEvaluation evaluation = createEvaluation(permission, executionContext, decision, parentPolicy);
 
-                policyProvider.evaluate(evaluation);
-                evaluation.denyIfNoEffect();
-            }
+            policyProvider.evaluate(evaluation);
 
             verified.compareAndSet(false, true);
         };
     }
 
-    private DefaultEvaluation createEvaluation(ResourcePermission permission, EvaluationContext executionContext, Decision decision, Policy parentPolicy, Policy associatedPolicy) {
-        return new DefaultEvaluation(permission, executionContext, parentPolicy, associatedPolicy, decision, authorization);
+    private DefaultEvaluation createEvaluation(ResourcePermission permission, EvaluationContext executionContext, Decision decision, Policy parentPolicy) {
+        return new DefaultEvaluation(permission, executionContext, parentPolicy, decision, authorization);
     }
 
     private boolean hasRequestedScopes(final ResourcePermission permission, final Policy policy) {
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 7fd6566..cdc0017 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
@@ -69,4 +69,9 @@ public interface Evaluation {
      * Denies the requested permission.
      */
     void deny();
+
+    /**
+     * Denies the requested permission if a decision was not made yet.
+     */
+    void denyIfNoEffect();
 }
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 df7c705..d86888d 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
@@ -58,62 +58,16 @@ public class PermissionTicketAwareDecisionResultCollector extends DecisionResult
     }
 
     @Override
-    protected void onDeny(Result result) {
-        ResourcePermission permission = result.getPermission();
-        Resource resource = permission.getResource();
-
-        if (resource != null && resource.isOwnerManagedAccess()) {
-            if (!resource.getOwner().equals(identity.getId())) {
-                Map<String, String> filters = new HashMap<>();
-
-                filters.put(PermissionTicket.RESOURCE, resource.getId());
-                filters.put(PermissionTicket.REQUESTER, identity.getId());
-                filters.put(PermissionTicket.GRANTED, Boolean.TRUE.toString());
-
-                List<PermissionTicket> permissions = authorization.getStoreFactory().getPermissionTicketStore().find(filters, resource.getResourceServer().getId(), -1, -1);
-
-                if (!permissions.isEmpty()) {
-                    List<Scope> grantedScopes = new ArrayList<>();
-
-                    for (PolicyResult policyResult : result.getResults()) {
-                        for (PermissionTicket ticket : permissions) {
-                            Scope grantedScope = ticket.getScope();
-
-                            if ("resource".equals(policyResult.getPolicy().getType())) {
-                                policyResult.setStatus(Effect.PERMIT);
-                            }
-
-                            if (grantedScope != null) {
-                                grantedScopes.add(grantedScope);
-
-                                for (Scope policyScope : policyResult.getPolicy().getScopes()) {
-                                    if (policyScope.equals(grantedScope)) {
-                                        policyResult.setStatus(Effect.PERMIT);
-                                    }
-                                }
-                            }
-                        }
-                    }
-
-                    permission.getScopes().clear();
-                    permission.getScopes().addAll(grantedScopes);
-                }
-            }
-        }
-
-        super.onDeny(result);
-    }
-
-    @Override
     public void onComplete() {
         super.onComplete();
 
         if (request.isSubmitRequest()) {
             StoreFactory storeFactory = authorization.getStoreFactory();
             ResourceStore resourceStore = storeFactory.getResourceStore();
+            List<PermissionTicketToken.ResourcePermission> resources = ticket.getResources();
 
-            if (ticket.getResources() != null) {
-                for (PermissionTicketToken.ResourcePermission permission : ticket.getResources()) {
+            if (resources != null) {
+                for (PermissionTicketToken.ResourcePermission permission : resources) {
                     Resource resource = resourceStore.findById(permission.getResourceId(), resourceServer.getId());
 
                     if (resource == null) {
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java
index d795d8a..1d353fd 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java
@@ -34,6 +34,10 @@ public interface PolicyProviderFactory<R extends AbstractPolicyRepresentation> e
 
     String getGroup();
 
+    default boolean isInternal() {
+        return false;
+    }
+
     PolicyProvider create(AuthorizationProvider authorization);
 
     R toRepresentation(Policy policy);
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/PermissionTicketStore.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/PermissionTicketStore.java
index 654d68b..a561712 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/PermissionTicketStore.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/PermissionTicketStore.java
@@ -90,4 +90,13 @@ public interface PermissionTicketStore {
     List<PermissionTicket> findByScope(String scopeId, String resourceServerId);
 
     List<PermissionTicket> find(Map<String, String> attributes, String resourceServerId, int firstResult, int maxResult);
+
+    /**
+     * Returns a list of {@link PermissionTicket} granted to the given {@code userId}.
+     *
+     * @param userId the user id
+     * @param resourceServerId the resource server id
+     * @return a list of permissions granted for a particular user
+     */
+    List<PermissionTicket> findGranted(String userId, String resourceServerId);
 }
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/UserManagedPermissionUtil.java b/server-spi-private/src/main/java/org/keycloak/authorization/UserManagedPermissionUtil.java
new file mode 100644
index 0000000..711d4d7
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/UserManagedPermissionUtil.java
@@ -0,0 +1,129 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.keycloak.authorization.model.PermissionTicket;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UserManagedPermissionUtil {
+
+    public static void updatePolicy(PermissionTicket ticket, StoreFactory storeFactory) {
+        Scope scope = ticket.getScope();
+        Policy policy = ticket.getPolicy();
+
+        if (policy == null) {
+            HashMap<String, String> filter = new HashMap<>();
+
+            filter.put(PermissionTicket.OWNER, ticket.getOwner());
+            filter.put(PermissionTicket.REQUESTER, ticket.getRequester());
+            filter.put(PermissionTicket.RESOURCE, ticket.getResource().getId());
+            filter.put(PermissionTicket.POLICY_IS_NOT_NULL, Boolean.TRUE.toString());
+
+            List<PermissionTicket> tickets = storeFactory.getPermissionTicketStore().find(filter, ticket.getResourceServer().getId(), -1, 1);
+
+            if (!tickets.isEmpty()) {
+                policy = tickets.iterator().next().getPolicy();
+            }
+        }
+
+        if (ticket.isGranted()) {
+            if (policy == null) {
+                policy = createUserManagedPermission(ticket, storeFactory);
+            }
+
+            if (scope != null && !policy.getScopes().contains(scope)) {
+                policy.addScope(scope);
+            }
+
+            ticket.setPolicy(policy);
+        } else if (scope != null) {
+            policy.removeScope(scope);
+            ticket.setPolicy(null);
+        }
+    }
+
+    public static void removePolicy(PermissionTicket ticket, StoreFactory storeFactory) {
+        Policy policy = ticket.getPolicy();
+
+        if (policy != null) {
+            HashMap<String, String> filter = new HashMap<>();
+
+            filter.put(PermissionTicket.OWNER, ticket.getOwner());
+            filter.put(PermissionTicket.REQUESTER, ticket.getRequester());
+            filter.put(PermissionTicket.RESOURCE, ticket.getResource().getId());
+            filter.put(PermissionTicket.GRANTED, Boolean.TRUE.toString());
+
+            List<PermissionTicket> tickets = storeFactory.getPermissionTicketStore().find(filter, ticket.getResourceServer().getId(), -1, -1);
+
+            if (tickets.isEmpty()) {
+                PolicyStore policyStore = storeFactory.getPolicyStore();
+
+                for (Policy associatedPolicy : policy.getAssociatedPolicies()) {
+                    policyStore.delete(associatedPolicy.getId());
+                }
+
+                policyStore.delete(policy.getId());
+            } else if (ticket.getScope() != null) {
+                policy.removeScope(ticket.getScope());
+            }
+        }
+    }
+
+    private static Policy createUserManagedPermission(PermissionTicket ticket, StoreFactory storeFactory) {
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+        UserPolicyRepresentation userPolicyRep = new UserPolicyRepresentation();
+
+        userPolicyRep.setName(KeycloakModelUtils.generateId());
+        userPolicyRep.addUser(ticket.getRequester());
+
+        Policy userPolicy = policyStore.create(userPolicyRep, ticket.getResourceServer());
+
+        userPolicy.setOwner(ticket.getOwner());
+
+        PolicyRepresentation policyRep = new PolicyRepresentation();
+
+        policyRep.setName(KeycloakModelUtils.generateId());
+        policyRep.setType("uma");
+        policyRep.addPolicy(userPolicy.getId());
+
+        Policy policy = policyStore.create(policyRep, ticket.getResourceServer());
+
+        policy.setOwner(ticket.getOwner());
+        policy.addResource(ticket.getResource());
+
+        Scope scope = ticket.getScope();
+
+        if (scope != null) {
+            policy.addScope(scope);
+        }
+
+        return policy;
+    }
+
+}
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 1deada1..fe449cd 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
@@ -2444,7 +2444,7 @@ public class RepresentationToModel {
         if (granted && !ticket.isGranted()) {
             ticket.setGrantedTimestamp(System.currentTimeMillis());
         } else if (!granted) {
-            ticket.setGrantedTimestamp(null);
+            ticketStore.delete(ticket.getId());
         }
 
         return ticket;
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
index e835ec6..cb87631 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
@@ -55,7 +55,6 @@ import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
 import org.keycloak.representations.idm.authorization.PolicyProviderRepresentation;
 import org.keycloak.representations.idm.authorization.PolicyRepresentation;
-import org.keycloak.representations.idm.authorization.ScopeRepresentation;
 import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
@@ -253,12 +252,13 @@ public class PolicyService {
         this.auth.realm().requireViewAuthorization();
         return Response.ok(
                 authorization.getProviderFactories().stream()
-                        .map(provider -> {
+                        .filter(factory -> !factory.isInternal())
+                        .map(factory -> {
                             PolicyProviderRepresentation representation = new PolicyProviderRepresentation();
 
-                            representation.setName(provider.getName());
-                            representation.setGroup(provider.getGroup());
-                            representation.setType(provider.getId());
+                            representation.setName(factory.getName());
+                            representation.setGroup(factory.getGroup());
+                            representation.setType(factory.getId());
 
                             return representation;
                         })
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 edde9cc..5e2ba95 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
@@ -164,17 +164,6 @@ public class ResourceSetService {
             return Response.status(Status.NOT_FOUND).build();
         }
 
-        PolicyStore policyStore = storeFactory.getPolicyStore();
-        List<Policy> policies = policyStore.findByResource(id, resourceServer.getId());
-
-        for (Policy policyModel : policies) {
-            if (policyModel.getResources().size() == 1) {
-                policyStore.delete(policyModel.getId());
-            } else {
-                policyModel.removeResource(resource);
-            }
-        }
-
         storeFactory.getResourceStore().delete(id);
 
         if (authorization.getRealm().isAdminEventsEnabled()) {
@@ -254,7 +243,8 @@ public class ResourceSetService {
     public Response getPermissions(@PathParam("id") String id) {
         requireView();
         StoreFactory storeFactory = authorization.getStoreFactory();
-        Resource model = storeFactory.getResourceStore().findById(id, resourceServer.getId());
+        ResourceStore resourceStore = storeFactory.getResourceStore();
+        Resource model = resourceStore.findById(id, resourceServer.getId());
 
         if (model == null) {
             return Response.status(Status.NOT_FOUND).build();
@@ -264,21 +254,36 @@ public class ResourceSetService {
         Set<Policy> policies = new HashSet<>();
 
         policies.addAll(policyStore.findByResource(model.getId(), resourceServer.getId()));
-        policies.addAll(policyStore.findByResourceType(model.getType(), resourceServer.getId()));
+
+        if (model.getType() != null) {
+            policies.addAll(policyStore.findByResourceType(model.getType(), resourceServer.getId()));
+
+            HashMap<String, String[]> resourceFilter = new HashMap<>();
+
+            resourceFilter.put("owner", new String[]{resourceServer.getId()});
+            resourceFilter.put("type", new String[]{model.getType()});
+
+            for (Resource resourceType : resourceStore.findByResourceServer(resourceFilter, resourceServer.getId(), -1, -1)) {
+                policies.addAll(policyStore.findByResource(resourceType.getId(), resourceServer.getId()));
+            }
+        }
+
         policies.addAll(policyStore.findByScopeIds(model.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toList()), id, resourceServer.getId()));
         policies.addAll(policyStore.findByScopeIds(model.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toList()), null, resourceServer.getId()));
 
         List<PolicyRepresentation> representation = new ArrayList<>();
 
         for (Policy policyModel : policies) {
-            PolicyRepresentation policy = new PolicyRepresentation();
+            if (!"uma".equalsIgnoreCase(policyModel.getType())) {
+                PolicyRepresentation policy = new PolicyRepresentation();
 
-            policy.setId(policyModel.getId());
-            policy.setName(policyModel.getName());
-            policy.setType(policyModel.getType());
+                policy.setId(policyModel.getId());
+                policy.setName(policyModel.getName());
+                policy.setType(policyModel.getType());
 
-            if (!representation.contains(policy)) {
-                representation.add(policy);
+                if (!representation.contains(policy)) {
+                    representation.add(policy);
+                }
             }
         }
 
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionTicketService.java b/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionTicketService.java
index 951a780..59ff1fd 100644
--- a/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionTicketService.java
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionTicketService.java
@@ -23,7 +23,10 @@ import org.keycloak.authorization.common.KeycloakIdentity;
 import org.keycloak.authorization.model.PermissionTicket;
 import org.keycloak.authorization.model.ResourceServer;
 import org.keycloak.authorization.store.PermissionTicketStore;
+import org.keycloak.authorization.store.StoreFactory;
 import org.keycloak.models.Constants;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserProvider;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.representations.idm.authorization.PermissionTicketRepresentation;
@@ -182,7 +185,8 @@ public class PermissionTicketService {
                          @QueryParam("returnNames") Boolean returnNames,
                          @QueryParam("first") Integer firstResult,
                          @QueryParam("max") Integer maxResult) {
-        PermissionTicketStore permissionTicketStore = authorization.getStoreFactory().getPermissionTicketStore();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        PermissionTicketStore permissionTicketStore = storeFactory.getPermissionTicketStore();
 
         Map<String, String> filters = new HashMap<>();
 
@@ -191,15 +195,22 @@ public class PermissionTicketService {
         }
 
         if (scopeId != null) {
-            filters.put(PermissionTicket.SCOPE, scopeId);
+            ScopeStore scopeStore = storeFactory.getScopeStore();
+            Scope scope = scopeStore.findById(scopeId, resourceServer.getId());
+
+            if (scope == null) {
+                scope = scopeStore.findByName(scopeId, resourceServer.getId());
+            }
+
+            filters.put(PermissionTicket.SCOPE, scope != null ? scope.getId() : scopeId);
         }
 
         if (owner != null) {
-            filters.put(PermissionTicket.OWNER, owner);
+            filters.put(PermissionTicket.OWNER, getUserId(owner));
         }
 
         if (requester != null) {
-            filters.put(PermissionTicket.REQUESTER, requester);
+            filters.put(PermissionTicket.REQUESTER, getUserId(requester));
         }
 
         if (granted != null) {
@@ -212,4 +223,22 @@ public class PermissionTicketService {
                         .collect(Collectors.toList()))
                 .build();
     }
+
+    private String getUserId(String userIdOrName) {
+        UserProvider userProvider = authorization.getKeycloakSession().users();
+        RealmModel realm = authorization.getRealm();
+        UserModel userModel = userProvider.getUserById(userIdOrName, realm);
+
+        if (userModel != null) {
+            return userModel.getId();
+        }
+
+        userModel = userProvider.getUserByUsername(userIdOrName, realm);
+
+        if (userModel != null) {
+            return userModel.getId();
+        }
+
+        return userIdOrName;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/authorization/util/Permissions.java b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
index 38b65b8..180ec33 100644
--- a/services/src/main/java/org/keycloak/authorization/util/Permissions.java
+++ b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
@@ -20,6 +20,7 @@ package org.keycloak.authorization.util;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
@@ -33,6 +34,7 @@ import javax.ws.rs.core.Response.Status;
 import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.Decision.Effect;
 import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.PermissionTicket;
 import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.model.Resource;
 import org.keycloak.authorization.model.ResourceServer;
@@ -71,9 +73,22 @@ public final class Permissions {
         StoreFactory storeFactory = authorization.getStoreFactory();
         ResourceStore resourceStore = storeFactory.getResourceStore();
 
+        // obtain all resources where owner is the resource server
         resourceStore.findByOwner(resourceServer.getId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, new LinkedList(resource.getScopes()), authorization)));
+
+        // obtain all resources where owner is the current user
         resourceStore.findByOwner(identity.getId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, new LinkedList(resource.getScopes()), authorization)));
 
+        // obtain all resources granted to the user via permission tickets (uma)
+        List<PermissionTicket> tickets = storeFactory.getPermissionTicketStore().findGranted(identity.getId(), resourceServer.getId());
+        Map<String, ResourcePermission> userManagedPermissions = new HashMap<>();
+
+        for (PermissionTicket ticket : tickets) {
+            userManagedPermissions.computeIfAbsent(ticket.getResource().getId(), id -> new ResourcePermission(ticket.getResource(), new ArrayList<>(), resourceServer));
+        }
+
+        permissions.addAll(userManagedPermissions.values());
+
         return permissions;
     }
 
@@ -156,7 +171,9 @@ public final class Permissions {
             boolean resourceDenied = false;
             ResourcePermission permission = result.getPermission();
             List<Result.PolicyResult> results = result.getResults();
+            List<Result.PolicyResult> userManagedPermissions = new ArrayList<>();
             int deniedCount = results.size();
+            Resource resource = permission.getResource();
 
             for (Result.PolicyResult policyResult : results) {
                 Policy policy = policyResult.getPolicy();
@@ -175,6 +192,8 @@ public final class Permissions {
                         // Later they will be filtered based on any denied scope, if any.
                         // TODO: we could probably provide a configuration option to let users decide whether or not a resource-based permission should grant all scopes associated with the resource.
                         grantedScopes.addAll(permission.getScopes());
+                    } if (resource.isOwnerManagedAccess() && "uma".equals(policy.getType())) {
+                        userManagedPermissions.add(policyResult);
                     }
                     deniedCount--;
                 } else {
@@ -183,7 +202,7 @@ public final class Permissions {
                         deniedScopes.addAll(policyScopes);
                     } else if (isResourcePermission(policy)) {
                         resourceDenied = true;
-                        deniedScopes.addAll(permission.getResource().getScopes());
+                        deniedScopes.addAll(resource.getScopes());
                     }
                 }
             }
@@ -193,6 +212,14 @@ public final class Permissions {
                 grantedScopes.removeAll(deniedScopes);
             }
 
+            for (Result.PolicyResult policyResult : userManagedPermissions) {
+                Policy policy = policyResult.getPolicy();
+
+                grantedScopes.addAll(policy.getScopes());
+
+                resourceDenied = false;
+            }
+
             // if there are no policy results is because the permission didn't match any policy.
             // In this case, if results is empty is because we are in permissive mode.
             if (!results.isEmpty()) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java
index 167761f..60bc6f8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java
@@ -23,7 +23,9 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.function.Supplier;
 
@@ -40,12 +42,16 @@ import org.keycloak.authorization.client.Configuration;
 import org.keycloak.authorization.client.util.HttpResponseException;
 import org.keycloak.common.util.Base64Url;
 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.AuthorizationRequest.Metadata;
 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.PermissionRequest;
+import org.keycloak.representations.idm.authorization.PermissionResponse;
+import org.keycloak.representations.idm.authorization.PermissionTicketRepresentation;
 import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceRepresentation;
 import org.keycloak.testsuite.util.ClientBuilder;
@@ -390,6 +396,108 @@ public class EntitlementAPITest extends AbstractAuthzTest {
                 PAIRWISE_AUTHZ_CLIENT_CONFIG);
     }
 
+    @Test
+    public void testObtainAllEntitlements() throws Exception {
+        ClientResource client = getClient(getRealm(), RESOURCE_SERVER_TEST);
+        AuthorizationResource authorization = client.authorization();
+
+        JSPolicyRepresentation policy = new JSPolicyRepresentation();
+
+        policy.setName("Only Owner Policy");
+        policy.setCode("if ($evaluation.getContext().getIdentity().getId() == $evaluation.getPermission().getResource().getOwner()) {$evaluation.grant();}");
+
+        authorization.policies().js().create(policy).close();
+
+        ResourceRepresentation resource = new ResourceRepresentation();
+
+        resource.setName("Marta Resource");
+        resource.setOwner("marta");
+        resource.setOwnerManagedAccess(true);
+
+        resource = authorization.resources().create(resource).readEntity(ResourceRepresentation.class);
+
+        ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
+
+        permission.setName("Marta Resource Permission");
+        permission.addResource(resource.getId());
+        permission.addPolicy(policy.getName());
+
+        authorization.permissions().resource().create(permission);
+
+        assertTrue(hasPermission("marta", "password", resource.getId()));
+        assertFalse(hasPermission("kolo", "password", resource.getId()));
+
+        String accessToken = new OAuthClient().realm("authz-test").clientId(RESOURCE_SERVER_TEST).doGrantAccessTokenRequest("secret", "kolo", "password").getAccessToken();
+        AuthzClient authzClient = getAuthzClient(AUTHZ_CLIENT_CONFIG);
+        PermissionResponse permissionResponse = authzClient.protection().permission().create(new PermissionRequest(resource.getId()));
+        AuthorizationRequest request = new AuthorizationRequest();
+
+        request.setTicket(permissionResponse.getTicket());
+
+        try {
+            authzClient.authorization(accessToken).authorize(request);
+        } catch (Exception ignore) {
+
+        }
+
+        List<PermissionTicketRepresentation> tickets = authzClient.protection().permission().findByResource(resource.getId());
+
+        assertEquals(1, tickets.size());
+
+        PermissionTicketRepresentation ticket = tickets.get(0);
+
+        ticket.setGranted(true);
+
+        authzClient.protection().permission().update(ticket);
+
+        assertTrue(hasPermission("kolo", "password", resource.getId()));
+
+        resource.addScope("Scope A");
+
+        authorization.resources().resource(resource.getId()).update(resource);
+
+        // the addition of a new scope invalidates the permission previously grante to the resource
+        assertFalse(hasPermission("kolo", "password", resource.getId()));
+
+        accessToken = new OAuthClient().realm("authz-test").clientId(RESOURCE_SERVER_TEST).doGrantAccessTokenRequest("secret", "kolo", "password").getAccessToken();
+        permissionResponse = authzClient.protection().permission().create(new PermissionRequest(resource.getId(), "Scope A"));
+        request = new AuthorizationRequest();
+
+        request.setTicket(permissionResponse.getTicket());
+
+        try {
+            authzClient.authorization(accessToken).authorize(request);
+        } catch (Exception ignore) {
+
+        }
+
+        tickets = authzClient.protection().permission().find(resource.getId(), "Scope A", null, null, false, false, null, null);
+
+        assertEquals(1, tickets.size());
+
+        ticket = tickets.get(0);
+
+        ticket.setGranted(true);
+
+        authzClient.protection().permission().update(ticket);
+
+        assertTrue(hasPermission("kolo", "password", resource.getId(), "Scope A"));
+
+        resource.addScope("Scope B");
+
+        authorization.resources().resource(resource.getId()).update(resource);
+
+        assertTrue(hasPermission("kolo", "password", resource.getId()));
+        assertFalse(hasPermission("kolo", "password", resource.getId(), "Scope B"));
+
+        resource.setScopes(new HashSet<>());
+
+        authorization.resources().resource(resource.getId()).update(resource);
+
+        assertTrue(hasPermission("kolo", "password", resource.getId()));
+        assertFalse(hasPermission("kolo", "password", resource.getId(), "Scope A"));
+    }
+
     public void testResourceServerAsAudience(String testClientId, String resourceServerClientId, String configFile) throws Exception {
         AuthorizationRequest request = new AuthorizationRequest();
 
@@ -402,6 +510,29 @@ public class EntitlementAPITest extends AbstractAuthzTest {
         assertEquals(resourceServerClientId, rpt.getAudience()[0]);
     }
 
+    private boolean hasPermission(String userName, String password, String resourceId, String... scopeIds) throws Exception {
+        String accessToken = new OAuthClient().realm("authz-test").clientId(RESOURCE_SERVER_TEST).doGrantAccessTokenRequest("secret", userName, password).getAccessToken();
+        AuthorizationResponse response = getAuthzClient(AUTHZ_CLIENT_CONFIG).authorization(accessToken).authorize(new AuthorizationRequest());
+        AccessToken rpt = toAccessToken(response.getToken());
+        Authorization authz = rpt.getAuthorization();
+        List<Permission> permissions = authz.getPermissions();
+
+        assertNotNull(permissions);
+        assertFalse(permissions.isEmpty());
+
+        for (Permission grantedPermission : permissions) {
+            if (grantedPermission.getResourceId().equals(resourceId)) {
+                return scopeIds == null || scopeIds.length == 0 || grantedPermission.getScopes().containsAll(Arrays.asList(scopeIds));
+            }
+        }
+
+        return false;
+    }
+
+    private boolean hasPermission(String userName, String password, String resourceId) throws Exception {
+        return hasPermission(userName, password, resourceId, null);
+    }
+
     private void assertResponse(Metadata metadata, Supplier<AuthorizationResponse> responseSupplier) {
         AccessToken.Authorization authorization = toAccessToken(responseSupplier.get().getToken()).getAuthorization();
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/GroupPathWithoutGroupClaimPolicyTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/GroupPathWithoutGroupClaimPolicyTest.java
new file mode 100644
index 0000000..3936308
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/GroupPathWithoutGroupClaimPolicyTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+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.authorization.client.AuthorizationDeniedException;
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.Configuration;
+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.UserRepresentation;
+import org.keycloak.representations.idm.authorization.AuthorizationRequest;
+import org.keycloak.representations.idm.authorization.AuthorizationResponse;
+import org.keycloak.representations.idm.authorization.GroupPolicyRepresentation;
+import org.keycloak.representations.idm.authorization.PermissionRequest;
+import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.testsuite.util.AdminClientUtil;
+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;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class GroupPathWithoutGroupClaimPolicyTest extends GroupPathPolicyTest {
+
+    @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");
+        groupProtocolMapper.setConfig(config);
+
+        testRealms.add(RealmBuilder.create().name("authz-test")
+                .roles(RolesBuilder.create()
+                        .realmRole(RoleBuilder.create().name("uma_authorization").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).build();
+                    }).collect(Collectors.toList())).build())
+                .group(GroupBuilder.create().name("Group E").build())
+                .user(UserBuilder.create().username("marta").password("password").addRoles("uma_authorization").addGroups("Group A"))
+                .user(UserBuilder.create().username("alice").password("password").addRoles("uma_authorization"))
+                .user(UserBuilder.create().username("kolo").password("password").addRoles("uma_authorization"))
+                .client(ClientBuilder.create().clientId("resource-server-test")
+                    .secret("secret")
+                    .authorizationServicesEnabled(true)
+                    .redirectUris("http://localhost/resource-server-test")
+                    .defaultRoles("uma_protection")
+                    .directAccessGrants())
+                .build());
+    }
+}
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 9d47f8d..aa9ce50 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
@@ -101,9 +101,20 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
 
     @Test
     public void testDeleteResourceAndPermissionTicket() throws Exception {
-        ResourceRepresentation resource = addResource("Resource A", true);
-        PermissionResponse response = getAuthzClient().protection().permission().create(new PermissionRequest(resource.getName()));
-        assertNotNull(response.getTicket());
+        ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB", "ScopeC");
+        AuthzClient authzClient = getAuthzClient();
+        PermissionResponse response = authzClient.protection("marta", "password").permission().create(new PermissionRequest(resource.getId(), "ScopeA", "ScopeB", "ScopeC"));
+        AuthorizationRequest request = new AuthorizationRequest();
+        request.setTicket(response.getTicket());
+        request.setClaimToken(authzClient.obtainAccessToken("marta", "password").getToken());
+
+        try {
+            authzClient.authorization().authorize(request);
+        } catch (Exception e) {
+
+        }
+
+        assertPersistence(response, resource, "ScopeA", "ScopeB", "ScopeC");
 
         getAuthzClient().protection().resource().delete(resource.getId());
         assertTrue(getAuthzClient().protection().permission().findByResource(resource.getId()).isEmpty());
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
index bedd4a7..1e5ec8f 100644
--- 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
@@ -665,6 +665,6 @@ public class PolicyEvaluationTest extends AbstractAuthzTest {
                 }
                 return baseAttributes;
             }
-        }, policy, policy, evaluation -> {}, authorization);
+        }, policy, evaluation -> {}, authorization);
     }
 }
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 5ef774e..7274ca5 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
@@ -56,7 +56,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         JSPolicyRepresentation policy = new JSPolicyRepresentation();
 
         policy.setName("Only Owner Policy");
-        policy.setCode("print($evaluation.getPermission().getResource().getOwner());print($evaluation.getContext().getIdentity().getId());if ($evaluation.getContext().getIdentity().getId() == $evaluation.getPermission().getResource().getOwner()) {$evaluation.grant();}");
+        policy.setCode("if ($evaluation.getContext().getIdentity().getId() == $evaluation.getPermission().getResource().getOwner()) {$evaluation.grant();}");
 
         Response response = authorization.policies().js().create(policy);
         response.close();
@@ -98,6 +98,90 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
         }
     }
 
+    /**
+     * Makes sure permissions granted to a typed resource instance does not grant access to resource instances with the same type.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testOnlyOwnerCanAccessResourceWithType() throws Exception {
+        ResourceRepresentation typedResource = addResource("Typed Resource", getClient(getRealm()).toRepresentation().getId(), false, "ScopeA", "ScopeB");
+
+        typedResource.setType("my:resource");
+
+        getClient(getRealm()).authorization().resources().resource(typedResource.getId()).update(typedResource);
+
+        resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
+
+        resource.setType(typedResource.getType());
+
+        getClient(getRealm()).authorization().resources().resource(resource.getId()).update(resource);
+
+        ResourceRepresentation resourceB = addResource("Resource B", "marta", true, "ScopeA", "ScopeB");
+
+        resourceB.setType(typedResource.getType());
+
+        getClient(getRealm()).authorization().resources().resource(resourceB.getId()).update(resourceB);
+
+        ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
+
+        permission.setName(resource.getType() + " Permission");
+        permission.setResourceType(resource.getType());
+        permission.addPolicy("Only Owner Policy");
+
+        getClient(getRealm()).authorization().permissions().resource().create(permission).close();
+
+        AuthorizationResponse response = authorize("marta", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
+        String rpt = response.getToken();
+
+        assertNotNull(rpt);
+        assertFalse(response.isUpgraded());
+
+        AccessToken accessToken = toAccessToken(rpt);
+        AccessToken.Authorization authorization = accessToken.getAuthorization();
+
+        assertNotNull(authorization);
+
+        List<Permission> permissions = authorization.getPermissions();
+
+        assertNotNull(permissions);
+        assertPermissions(permissions, resource.getName(), "ScopeA", "ScopeB");
+        assertTrue(permissions.isEmpty());
+
+        try {
+            response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
+            fail("User should not have access to resource from another user");
+        } catch (AuthorizationDeniedException ade) {
+
+        }
+
+        List<PermissionTicketRepresentation> tickets = getAuthzClient().protection().permission().find(resource.getId(), null, null, null, null, null, null, null);
+
+        for (PermissionTicketRepresentation ticket : tickets) {
+            ticket.setGranted(true);
+            getAuthzClient().protection().permission().update(ticket);
+        }
+
+        try {
+            response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
+        } catch (AuthorizationDeniedException ade) {
+            fail("User should have access to resource from another user");
+        }
+
+        permissions = authorization.getPermissions();
+
+        assertNotNull(permissions);
+        assertPermissions(permissions, resource.getName(), "ScopeA", "ScopeB");
+        assertTrue(permissions.isEmpty());
+
+        try {
+            response = authorize("kolo", "password", resourceB.getId(), new String[] {"ScopeA", "ScopeB"});
+            fail("User should not have access to resource from another user");
+        } catch (AuthorizationDeniedException ade) {
+
+        }
+    }
+
     @Test
     public void testUserGrantsAccessToResource() throws Exception {
         ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
@@ -306,7 +390,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
 
         try {
             response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA"});
-            fail("User should have access to resource from another user");
+            fail("User should not have access to resource from another user");
         } catch (AuthorizationDeniedException ade) {
 
         }