[KEYCLOAK-12735] - Improving queries and cache for authz

This commit is contained in:
Pedro Igor 2020-03-13 12:28:34 -03:00 committed by Hynek Mlnařík
parent 874642fe9e
commit 601bf8d63e
6 changed files with 30 additions and 29 deletions

View file

@ -56,10 +56,10 @@ import org.keycloak.representations.idm.authorization.Logic;
{
@NamedQuery(name="findPolicyIdByServerId", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId "),
@NamedQuery(name="findPolicyIdByName", query="select p from PolicyEntity p left join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and p.name = :name"),
@NamedQuery(name="findPolicyIdByResource", query="select p from PolicyEntity p inner join fetch p.resources r left join fetch p.scopes s inner join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"),
@NamedQuery(name="findPolicyIdByScope", query="select pe from PolicyEntity pe left join fetch pe.resources r inner join fetch pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id))"),
@NamedQuery(name="findPolicyIdByResourceScope", query="select pe from PolicyEntity pe inner join fetch pe.resources r inner join fetch pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id)) and exists (select p.id from ResourceEntity r inner join r.policies p where r.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and r.id in (:resourceId)))"),
@NamedQuery(name="findPolicyIdByNullResourceScope", query="select pe from PolicyEntity pe left join fetch pe.resources r inner join fetch pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and s.id in (:scopeIds))) and pe.resources is empty"),
@NamedQuery(name="findPolicyIdByResource", query="select p from PolicyEntity p inner join p.resources r inner join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"),
@NamedQuery(name="findPolicyIdByScope", query="select pe from PolicyEntity pe inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id))"),
@NamedQuery(name="findPolicyIdByResourceScope", query="select pe from PolicyEntity pe inner join pe.resources r inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id)) and exists (select p.id from ResourceEntity r inner join r.policies p where r.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and r.id in (:resourceId)))"),
@NamedQuery(name="findPolicyIdByNullResourceScope", query="select pe from PolicyEntity pe inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and s.id in (:scopeIds))) and pe.resources is empty"),
@NamedQuery(name="findPolicyIdByType", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type"),
@NamedQuery(name="findPolicyIdByResourceType", query="select p from PolicyEntity p inner join p.config c inner join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type"),
@NamedQuery(name="findPolicyIdByDependentPolices", query="select p.id from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)"),

View file

@ -57,10 +57,10 @@ import org.hibernate.annotations.FetchMode;
})
@NamedQueries(
{
@NamedQuery(name="findResourceIdByOwner", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.resourceServer.id = :serverId and r.owner = :owner"),
@NamedQuery(name="findResourceIdByOwnerOrdered", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.resourceServer.id = :serverId and r.owner = :owner order by r.id"),
@NamedQuery(name="findAnyResourceIdByOwner", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.owner = :owner"),
@NamedQuery(name="findAnyResourceIdByOwnerOrdered", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.owner = :owner order by r.id"),
@NamedQuery(name="findResourceIdByOwner", query="select distinct(r.id) from ResourceEntity r left join r.scopes s where r.resourceServer.id = :serverId and r.owner = :owner"),
@NamedQuery(name="findResourceIdByOwnerOrdered", query="select distinct(r.id) from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner order by r.id"),
@NamedQuery(name="findAnyResourceIdByOwner", query="select distinct(r.id) from ResourceEntity r where r.owner = :owner"),
@NamedQuery(name="findAnyResourceIdByOwnerOrdered", query="select distinct(r.id) from ResourceEntity r where r.owner = :owner order by r.id"),
@NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and :uri in elements(r.uris)"),
@NamedQuery(name="findResourceIdByName", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.resourceServer.id = :serverId and r.owner = :ownerId and r.name = :name"),
@NamedQuery(name="findResourceIdByType", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.resourceServer.id = :serverId and r.owner = :ownerId and r.type = :type"),

View file

@ -130,7 +130,7 @@ public class JPAResourceStore implements ResourceStore {
queryName = pagination ? "findAnyResourceIdByOwnerOrdered" : "findAnyResourceIdByOwner";
}
TypedQuery<ResourceEntity> query = entityManager.createNamedQuery(queryName, ResourceEntity.class);
TypedQuery<String> query = entityManager.createNamedQuery(queryName, String.class);
query.setFlushMode(FlushModeType.COMMIT);
query.setParameter("owner", ownerId);
@ -145,10 +145,10 @@ public class JPAResourceStore implements ResourceStore {
}
ResourceStore resourceStore = provider.getStoreFactory().getResourceStore();
List<ResourceEntity> result = query.getResultList();
List<String> result = query.getResultList();
for (ResourceEntity entity : result) {
Resource cached = resourceStore.findById(entity.getId(), resourceServerId);
for (String entity : result) {
Resource cached = resourceStore.findById(entity, resourceServerId);
if (cached != null) {
consumer.accept(cached);

View file

@ -244,7 +244,7 @@ public class ResourceAdapter extends AbstractAuthorizationModel implements Resou
@Override
public boolean isFetched(String association) {
return em.getEntityManagerFactory().getPersistenceUnitUtil().isLoaded(this, association);
return em.getEntityManagerFactory().getPersistenceUnitUtil().isLoaded(this.entity, association);
}

View file

@ -19,6 +19,7 @@ package org.keycloak.authorization.authorization;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@ -94,6 +95,7 @@ import org.keycloak.services.util.DefaultClientSessionContext;
public class AuthorizationTokenService {
public static final String CLAIM_TOKEN_FORMAT_ID_TOKEN = "http://openid.net/specs/openid-connect-core-1_0.html#IDToken";
public static final String CLAIM_TOKEN_FORMAT_JWT = "urn:ietf:params:oauth:token-type:jwt";
private static final Logger logger = Logger.getLogger(AuthorizationTokenService.class);
private static final String RESPONSE_MODE_DECISION = "decision";
@ -103,12 +105,11 @@ public class AuthorizationTokenService {
static {
SUPPORTED_CLAIM_TOKEN_FORMATS = new HashMap<>();
SUPPORTED_CLAIM_TOKEN_FORMATS.put("urn:ietf:params:oauth:token-type:jwt", (request, authorization) -> {
SUPPORTED_CLAIM_TOKEN_FORMATS.put(CLAIM_TOKEN_FORMAT_JWT, (request, authorization) -> {
Map claims = request.getClaims();
String claimToken = request.getClaimToken();
if (claimToken != null) {
Map claims;
try {
claims = JsonSerialization.readValue(Base64Url.decode(request.getClaimToken()), Map.class);
request.setClaims(claims);
@ -116,20 +117,18 @@ public class AuthorizationTokenService {
throw new CorsErrorResponseException(request.getCors(), "invalid_request", "Invalid claims",
Status.BAD_REQUEST);
}
KeycloakIdentity identity;
try {
identity = new KeycloakIdentity(authorization.getKeycloakSession(),
Tokens.getAccessToken(request.getSubjectToken(), authorization.getKeycloakSession()));
} catch (Exception cause) {
throw new CorsErrorResponseException(request.getCors(), "unauthorized_client", "Invalid identity", Status.BAD_REQUEST);
}
return new DefaultEvaluationContext(identity, claims, authorization.getKeycloakSession());
}
throw new CorsErrorResponseException(request.getCors(), "invalid_request", "Claim token can not be null", Status.BAD_REQUEST);
KeycloakIdentity identity;
try {
identity = new KeycloakIdentity(authorization.getKeycloakSession(),
Tokens.getAccessToken(request.getSubjectToken(), authorization.getKeycloakSession()));
} catch (Exception cause) {
throw new CorsErrorResponseException(request.getCors(), "unauthorized_client", "Invalid identity", Status.BAD_REQUEST);
}
return new DefaultEvaluationContext(identity, claims, authorization.getKeycloakSession());
});
SUPPORTED_CLAIM_TOKEN_FORMATS.put(CLAIM_TOKEN_FORMAT_ID_TOKEN, (request, authorization) -> {
KeycloakSession keycloakSession = authorization.getKeycloakSession();
@ -397,7 +396,7 @@ public class AuthorizationTokenService {
String claimTokenFormat = request.getClaimTokenFormat();
if (claimTokenFormat == null) {
claimTokenFormat = CLAIM_TOKEN_FORMAT_ID_TOKEN;
claimTokenFormat = CLAIM_TOKEN_FORMAT_JWT;
}
BiFunction<KeycloakAuthorizationRequest, AuthorizationProvider, EvaluationContext> evaluationContextProvider = SUPPORTED_CLAIM_TOKEN_FORMATS.get(claimTokenFormat);

View file

@ -5,6 +5,7 @@ import javax.ws.rs.core.Response;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.performance.dataset.idm.Client;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.performance.dataset.NestedEntity;
import org.keycloak.performance.dataset.Updatable;
@ -46,6 +47,7 @@ public class ResourceServer extends NestedEntity<Client, ResourceServerRepresent
r.setId(getClient().getRepresentation().getId());
r.setClientId(getClient().getRepresentation().getClientId());
r.setName(getClient().getRepresentation().getName());
r.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
return r;
}