keycloak-aplcache
Changes
services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java 14(+8 -6)
Details
diff --git a/server-spi-private/src/main/java/org/keycloak/events/admin/ResourceType.java b/server-spi-private/src/main/java/org/keycloak/events/admin/ResourceType.java
index cba5ed6..128b344 100644
--- a/server-spi-private/src/main/java/org/keycloak/events/admin/ResourceType.java
+++ b/server-spi-private/src/main/java/org/keycloak/events/admin/ResourceType.java
@@ -156,5 +156,25 @@ public enum ResourceType {
/**
*
*/
- , COMPONENT;
+ , COMPONENT
+
+ /**
+ *
+ */
+ , AUTHORIZATION_RESOURCE_SERVER
+
+ /**
+ *
+ */
+ , AUTHORIZATION_RESOURCE
+
+ /**
+ *
+ */
+ , AUTHORIZATION_SCOPE
+
+ /**
+ *
+ */
+ , AUTHORIZATION_POLICY;
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 7431ed2..bdde153 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -772,11 +772,7 @@ public class ModelToRepresentation {
return rep;
}
- public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider) {
- return toRepresentation(model, authorizationProvider, true);
- }
-
- public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider, boolean deep) {
+ public static ScopeRepresentation toRepresentation(Scope model) {
ScopeRepresentation scope = new ScopeRepresentation();
scope.setId(model.getId());
diff --git a/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java b/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java
index a4ff868..bc9dd1f 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java
@@ -23,6 +23,7 @@ import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
import javax.ws.rs.Path;
@@ -34,14 +35,14 @@ public class AuthorizationService {
private final RealmAuth auth;
private final ClientModel client;
- private final KeycloakSession session;
private final ResourceServer resourceServer;
private final AuthorizationProvider authorization;
+ private final AdminEventBuilder adminEvent;
- public AuthorizationService(KeycloakSession session, ClientModel client, RealmAuth auth) {
- this.session = session;
+ public AuthorizationService(KeycloakSession session, ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
this.client = client;
this.authorization = session.getProvider(AuthorizationProvider.class);
+ this.adminEvent = adminEvent;
this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().findByClient(this.client.getId());
this.auth = auth;
@@ -52,16 +53,16 @@ public class AuthorizationService {
@Path("/resource-server")
public ResourceServerService resourceServer() {
- ResourceServerService resource = new ResourceServerService(this.authorization, this.resourceServer, this.client, this.auth);
+ ResourceServerService resource = new ResourceServerService(this.authorization, this.resourceServer, this.client, this.auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(resource);
return resource;
}
- public void enable() {
+ public void enable(boolean newClient) {
if (!isEnabled()) {
- resourceServer().create();
+ resourceServer().create(newClient);
}
}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PermissionService.java b/services/src/main/java/org/keycloak/authorization/admin/PermissionService.java
index ba4fae2..ea4677d 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PermissionService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PermissionService.java
@@ -22,6 +22,7 @@ import java.util.Map;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
/**
@@ -29,18 +30,18 @@ import org.keycloak.services.resources.admin.RealmAuth;
*/
public class PermissionService extends PolicyService {
- public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
- super(resourceServer, authorization, auth);
+ public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+ super(resourceServer, authorization, auth, adminEvent);
}
@Override
protected PolicyResourceService doCreatePolicyResource(Policy policy) {
- return new PolicyTypeResourceService(policy, resourceServer, authorization, auth);
+ return new PolicyTypeResourceService(policy, resourceServer, authorization, auth, adminEvent);
}
@Override
protected PolicyTypeService doCreatePolicyTypeResource(String type) {
- return new PolicyTypeService(type, resourceServer, authorization, auth) {
+ return new PolicyTypeService(type, resourceServer, authorization, auth, adminEvent) {
@Override
protected List<Object> doSearch(Integer firstResult, Integer maxResult, Map<String, String[]> filters) {
filters.put("permission", new String[] {Boolean.TRUE.toString()});
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
index 85e0943..c0728bc 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
@@ -26,8 +26,10 @@ import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.authorization.AuthorizationProvider;
@@ -36,12 +38,15 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
import org.keycloak.util.JsonSerialization;
@@ -54,19 +59,21 @@ public class PolicyResourceService {
protected final ResourceServer resourceServer;
protected final AuthorizationProvider authorization;
protected final RealmAuth auth;
+ private final AdminEventBuilder adminEvent;
- public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
+ public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
this.policy = policy;
this.resourceServer = resourceServer;
this.authorization = authorization;
this.auth = auth;
+ this.adminEvent = adminEvent.resource(ResourceType.AUTHORIZATION_POLICY);
}
@PUT
@Consumes("application/json")
@Produces("application/json")
@NoCache
- public Response update(String payload) {
+ public Response update(@Context UriInfo uriInfo, String payload) {
this.auth.requireManage();
AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
@@ -79,11 +86,14 @@ public class PolicyResourceService {
RepresentationToModel.toModel(representation, authorization, policy);
+
+ audit(uriInfo, representation, OperationType.UPDATE);
+
return Response.status(Status.CREATED).build();
}
@DELETE
- public Response delete() {
+ public Response delete(@Context UriInfo uriInfo) {
this.auth.requireManage();
if (policy == null) {
@@ -98,6 +108,10 @@ public class PolicyResourceService {
policyStore.delete(policy.getId());
+ if (authorization.getRealm().isAdminEventsEnabled()) {
+ audit(uriInfo, toRepresentation(policy, authorization), OperationType.DELETE);
+ }
+
return Response.noContent().build();
}
@@ -225,4 +239,10 @@ public class PolicyResourceService {
protected Policy getPolicy() {
return policy;
}
+
+ private void audit(@Context UriInfo uriInfo, AbstractPolicyRepresentation policy, OperationType operation) {
+ if (authorization.getRealm().isAdminEventsEnabled()) {
+ adminEvent.operation(operation).resourcePath(uriInfo).representation(policy).success();
+ }
+ }
}
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 e670042..e8d4aa8 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
@@ -33,9 +33,11 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
@@ -46,12 +48,16 @@ import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.Constants;
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.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
import org.keycloak.util.JsonSerialization;
@@ -63,11 +69,13 @@ public class PolicyService {
protected final ResourceServer resourceServer;
protected final AuthorizationProvider authorization;
protected final RealmAuth auth;
+ protected final AdminEventBuilder adminEvent;
- public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
+ public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
this.resourceServer = resourceServer;
this.authorization = authorization;
this.auth = auth;
+ this.adminEvent = adminEvent.resource(ResourceType.AUTHORIZATION_POLICY);
}
@Path("{type}")
@@ -84,18 +92,18 @@ public class PolicyService {
}
protected PolicyTypeService doCreatePolicyTypeResource(String type) {
- return new PolicyTypeService(type, resourceServer, authorization, auth);
+ return new PolicyTypeService(type, resourceServer, authorization, auth, adminEvent);
}
protected Object doCreatePolicyResource(Policy policy) {
- return new PolicyResourceService(policy, resourceServer, authorization, auth);
+ return new PolicyResourceService(policy, resourceServer, authorization, auth, adminEvent);
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@NoCache
- public Response create(String payload) {
+ public Response create(@Context UriInfo uriInfo, String payload) {
this.auth.requireManage();
AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
@@ -103,6 +111,8 @@ public class PolicyService {
representation.setId(policy.getId());
+ audit(uriInfo, representation, representation.getId(), OperationType.CREATE);
+
return Response.status(Status.CREATED).entity(representation).build();
}
@@ -280,4 +290,14 @@ public class PolicyService {
findAssociatedPolicies(associated, policies);
});
}
+
+ private void audit(@Context UriInfo uriInfo, AbstractPolicyRepresentation resource, String id, OperationType operation) {
+ if (authorization.getRealm().isAdminEventsEnabled()) {
+ if (id != null) {
+ adminEvent.operation(operation).resourcePath(uriInfo, id).representation(resource).success();
+ } else {
+ adminEvent.operation(operation).resourcePath(uriInfo).representation(resource).success();
+ }
+ }
+ }
}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java
index 8756721..9044c0d 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java
@@ -24,6 +24,7 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
import org.keycloak.util.JsonSerialization;
@@ -32,8 +33,8 @@ import org.keycloak.util.JsonSerialization;
*/
public class PolicyTypeResourceService extends PolicyResourceService {
- public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
- super(policy, resourceServer, authorization, auth);
+ public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+ super(policy, resourceServer, authorization, auth, adminEvent);
}
@Override
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeService.java
index 5f03dad..6f37f6c 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeService.java
@@ -30,6 +30,7 @@ import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
import org.keycloak.util.JsonSerialization;
@@ -40,8 +41,8 @@ public class PolicyTypeService extends PolicyService {
private final String type;
- PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
- super(resourceServer, authorization, auth);
+ PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+ super(resourceServer, authorization, auth, adminEvent);
this.type = type;
}
@@ -60,7 +61,7 @@ public class PolicyTypeService extends PolicyService {
@Override
protected Object doCreatePolicyResource(Policy policy) {
- return new PolicyTypeResourceService(policy, resourceServer,authorization, auth);
+ return new PolicyTypeResourceService(policy, resourceServer,authorization, auth, adminEvent);
}
@Override
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
index 15f1db7..777d843 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
@@ -40,12 +40,15 @@ import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
import org.keycloak.exportimport.util.ExportUtils;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic;
@@ -53,6 +56,7 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
/**
@@ -62,19 +66,24 @@ public class ResourceServerService {
private final AuthorizationProvider authorization;
private final RealmAuth auth;
+ private final AdminEventBuilder adminEvent;
private final KeycloakSession session;
private ResourceServer resourceServer;
private final ClientModel client;
- public ResourceServerService(AuthorizationProvider authorization, ResourceServer resourceServer, ClientModel client, RealmAuth auth) {
+ @Context
+ private UriInfo uriInfo;
+
+ public ResourceServerService(AuthorizationProvider authorization, ResourceServer resourceServer, ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
this.authorization = authorization;
this.session = authorization.getKeycloakSession();
this.client = client;
this.resourceServer = resourceServer;
this.auth = auth;
+ this.adminEvent = adminEvent;
}
- public void create() {
+ public void create(boolean newClient) {
this.auth.requireManage();
UserModel serviceAccount = this.session.users().getServiceAccount(client);
@@ -86,16 +95,17 @@ public class ResourceServerService {
this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().create(this.client.getId());
createDefaultRoles(serviceAccount);
createDefaultPermission(createDefaultResource(), createDefaultPolicy());
+ audit(OperationType.CREATE, uriInfo, newClient);
}
@PUT
@Consumes("application/json")
@Produces("application/json")
- public Response update(ResourceServerRepresentation server) {
+ public Response update(@Context UriInfo uriInfo, ResourceServerRepresentation server) {
this.auth.requireManage();
this.resourceServer.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement());
this.resourceServer.setPolicyEnforcementMode(server.getPolicyEnforcementMode());
-
+ audit(OperationType.UPDATE, uriInfo, false);
return Response.noContent().build();
}
@@ -105,17 +115,19 @@ public class ResourceServerService {
ResourceStore resourceStore = storeFactory.getResourceStore();
String id = resourceServer.getId();
+ PolicyStore policyStore = storeFactory.getPolicyStore();
+
+ policyStore.findByResourceServer(id).forEach(scope -> policyStore.delete(scope.getId()));
+
resourceStore.findByResourceServer(id).forEach(resource -> resourceStore.delete(resource.getId()));
ScopeStore scopeStore = storeFactory.getScopeStore();
scopeStore.findByResourceServer(id).forEach(scope -> scopeStore.delete(scope.getId()));
- PolicyStore policyStore = storeFactory.getPolicyStore();
-
- policyStore.findByResourceServer(id).forEach(scope -> policyStore.delete(scope.getId()));
-
storeFactory.getResourceServerStore().delete(id);
+
+ audit(OperationType.DELETE, uriInfo, false);
}
@GET
@@ -143,12 +155,14 @@ public class ResourceServerService {
RepresentationToModel.toModel(rep, authorization);
+ audit(OperationType.UPDATE, uriInfo, false);
+
return Response.noContent().build();
}
@Path("/resource")
public ResourceSetService getResourceSetResource() {
- ResourceSetService resource = new ResourceSetService(this.resourceServer, this.authorization, this.auth);
+ ResourceSetService resource = new ResourceSetService(this.resourceServer, this.authorization, this.auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(resource);
@@ -157,7 +171,7 @@ public class ResourceServerService {
@Path("/scope")
public ScopeService getScopeResource() {
- ScopeService resource = new ScopeService(this.resourceServer, this.authorization, this.auth);
+ ScopeService resource = new ScopeService(this.resourceServer, this.authorization, this.auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(resource);
@@ -166,7 +180,7 @@ public class ResourceServerService {
@Path("/policy")
public PolicyService getPolicyResource() {
- PolicyService resource = new PolicyService(this.resourceServer, this.authorization, this.auth);
+ PolicyService resource = new PolicyService(this.resourceServer, this.authorization, this.auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(resource);
@@ -176,7 +190,7 @@ public class ResourceServerService {
@Path("/permission")
public Object getPermissionTypeResource() {
this.auth.requireView();
- PermissionService resource = new PermissionService(this.resourceServer, this.authorization, this.auth);
+ PermissionService resource = new PermissionService(this.resourceServer, this.authorization, this.auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(resource);
@@ -239,4 +253,14 @@ public class ResourceServerService {
serviceAccount.grantRole(umaProtectionRole);
}
}
+
+ private void audit(OperationType operation, UriInfo uriInfo, boolean newClient) {
+ if (newClient) {
+ adminEvent.resource(ResourceType.AUTHORIZATION_RESOURCE_SERVER).operation(operation).resourcePath(uriInfo, client.getId())
+ .representation(ModelToRepresentation.toRepresentation(resourceServer, client)).success();
+ } else {
+ adminEvent.resource(ResourceType.AUTHORIZATION_RESOURCE_SERVER).operation(operation).resourcePath(uriInfo)
+ .representation(ModelToRepresentation.toRepresentation(resourceServer, client)).success();
+ }
+ }
}
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 5d65923..b0666f1 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
@@ -26,6 +26,8 @@ import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
@@ -37,6 +39,7 @@ import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentatio
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
import javax.ws.rs.Consumes;
@@ -48,8 +51,10 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.Collections;
@@ -70,17 +75,25 @@ public class ResourceSetService {
private final AuthorizationProvider authorization;
private final RealmAuth auth;
+ private final AdminEventBuilder adminEvent;
private ResourceServer resourceServer;
- public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
+ public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
this.resourceServer = resourceServer;
this.authorization = authorization;
this.auth = auth;
+ this.adminEvent = adminEvent.resource(ResourceType.AUTHORIZATION_RESOURCE);
}
@POST
@Consumes("application/json")
@Produces("application/json")
+ public Response create(@Context UriInfo uriInfo, ResourceRepresentation resource) {
+ Response response = create(resource);
+ audit(uriInfo, resource, resource.getId(), OperationType.CREATE);
+ return response;
+ }
+
public Response create(ResourceRepresentation resource) {
requireManage();
StoreFactory storeFactory = this.authorization.getStoreFactory();
@@ -128,7 +141,7 @@ public class ResourceSetService {
@PUT
@Consumes("application/json")
@Produces("application/json")
- public Response update(@PathParam("id") String id, ResourceRepresentation resource) {
+ public Response update(@Context UriInfo uriInfo, @PathParam("id") String id, ResourceRepresentation resource) {
requireManage();
resource.setId(id);
StoreFactory storeFactory = this.authorization.getStoreFactory();
@@ -141,12 +154,14 @@ public class ResourceSetService {
toModel(resource, resourceServer, authorization);
+ audit(uriInfo, resource, OperationType.UPDATE);
+
return Response.noContent().build();
}
@Path("{id}")
@DELETE
- public Response delete(@PathParam("id") String id) {
+ public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
requireManage();
StoreFactory storeFactory = authorization.getStoreFactory();
Resource resource = storeFactory.getResourceStore().findById(id, resourceServer.getId());
@@ -168,6 +183,10 @@ public class ResourceSetService {
storeFactory.getResourceStore().delete(id);
+ if (authorization.getRealm().isAdminEventsEnabled()) {
+ audit(uriInfo, toRepresentation(resource, resourceServer, authorization), OperationType.DELETE);
+ }
+
return Response.noContent().build();
}
@@ -376,4 +395,18 @@ public class ResourceSetService {
this.auth.requireManage();
}
}
+
+ private void audit(@Context UriInfo uriInfo, ResourceRepresentation resource, OperationType operation) {
+ audit(uriInfo, resource, null, operation);
+ }
+
+ private void audit(@Context UriInfo uriInfo, ResourceRepresentation resource, String id, OperationType operation) {
+ if (authorization.getRealm().isAdminEventsEnabled()) {
+ if (id != null) {
+ adminEvent.operation(operation).resourcePath(uriInfo, id).representation(resource).success();
+ } else {
+ adminEvent.operation(operation).resourcePath(uriInfo).representation(resource).success();
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java b/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java
index 1ec9a13..d59a6de 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java
@@ -25,11 +25,14 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.Constants;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth;
import javax.ws.rs.Consumes;
@@ -41,9 +44,11 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
import java.util.Arrays;
import java.util.HashMap;
@@ -61,23 +66,27 @@ public class ScopeService {
private final AuthorizationProvider authorization;
private final RealmAuth auth;
+ private final AdminEventBuilder adminEvent;
private ResourceServer resourceServer;
- public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
+ public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
this.resourceServer = resourceServer;
this.authorization = authorization;
this.auth = auth;
+ this.adminEvent = adminEvent.resource(ResourceType.AUTHORIZATION_SCOPE);
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- public Response create(ScopeRepresentation scope) {
+ public Response create(@Context UriInfo uriInfo, ScopeRepresentation scope) {
this.auth.requireManage();
Scope model = toModel(scope, this.resourceServer, authorization);
scope.setId(model.getId());
+ audit(uriInfo, scope, scope.getId(), OperationType.CREATE);
+
return Response.status(Status.CREATED).entity(scope).build();
}
@@ -85,7 +94,7 @@ public class ScopeService {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- public Response update(@PathParam("id") String id, ScopeRepresentation scope) {
+ public Response update(@Context UriInfo uriInfo, @PathParam("id") String id, ScopeRepresentation scope) {
this.auth.requireManage();
scope.setId(id);
StoreFactory storeFactory = authorization.getStoreFactory();
@@ -97,12 +106,14 @@ public class ScopeService {
toModel(scope, resourceServer, authorization);
+ audit(uriInfo, scope, OperationType.UPDATE);
+
return Response.noContent().build();
}
@Path("{id}")
@DELETE
- public Response delete(@PathParam("id") String id) {
+ public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
this.auth.requireManage();
StoreFactory storeFactory = authorization.getStoreFactory();
List<Resource> resources = storeFactory.getResourceStore().findByScope(Arrays.asList(id), resourceServer.getId());
@@ -130,6 +141,10 @@ public class ScopeService {
storeFactory.getScopeStore().delete(id);
+ if (authorization.getRealm().isAdminEventsEnabled()) {
+ audit(uriInfo, toRepresentation(scope), OperationType.DELETE);
+ }
+
return Response.noContent().build();
}
@@ -144,7 +159,7 @@ public class ScopeService {
return Response.status(Status.NOT_FOUND).build();
}
- return Response.ok(toRepresentation(model, this.authorization)).build();
+ return Response.ok(toRepresentation(model)).build();
}
@Path("{id}/resources")
@@ -212,22 +227,17 @@ public class ScopeService {
return Response.status(Status.OK).build();
}
- return Response.ok(toRepresentation(model, authorization)).build();
+ return Response.ok(toRepresentation(model)).build();
}
@GET
@Produces("application/json")
public Response findAll(@QueryParam("scopeId") String id,
@QueryParam("name") String name,
- @QueryParam("deep") Boolean deep,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResult) {
this.auth.requireView();
- if (deep == null) {
- deep = true;
- }
-
Map<String, String[]> search = new HashMap<>();
if (id != null && !"".equals(id.trim())) {
@@ -238,11 +248,24 @@ public class ScopeService {
search.put("name", new String[] {name});
}
- Boolean finalDeep = deep;
return Response.ok(
this.authorization.getStoreFactory().getScopeStore().findByResourceServer(search, this.resourceServer.getId(), firstResult != null ? firstResult : -1, maxResult != null ? maxResult : Constants.DEFAULT_MAX_RESULTS).stream()
- .map(scope -> toRepresentation(scope, this.authorization, finalDeep))
+ .map(scope -> toRepresentation(scope))
.collect(Collectors.toList()))
.build();
}
+
+ private void audit(@Context UriInfo uriInfo, ScopeRepresentation resource, OperationType operation) {
+ audit(uriInfo, resource, null, operation);
+ }
+
+ private void audit(@Context UriInfo uriInfo, ScopeRepresentation resource, String id, OperationType operation) {
+ if (authorization.getRealm().isAdminEventsEnabled()) {
+ if (id != null) {
+ adminEvent.operation(operation).resourcePath(uriInfo, id).representation(resource).success();
+ } else {
+ adminEvent.operation(operation).resourcePath(uriInfo).representation(resource).success();
+ }
+ }
+ }
}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/ProtectionService.java b/services/src/main/java/org/keycloak/authorization/protection/ProtectionService.java
index 45fb6fe..3779279 100644
--- a/services/src/main/java/org/keycloak/authorization/protection/ProtectionService.java
+++ b/services/src/main/java/org/keycloak/authorization/protection/ProtectionService.java
@@ -27,12 +27,17 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.protection.permission.PermissionService;
import org.keycloak.authorization.protection.permission.PermissionsService;
import org.keycloak.authorization.protection.resource.ResourceService;
+import org.keycloak.common.ClientConnection;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.resources.admin.AdminAuth;
+import org.keycloak.services.resources.admin.AdminEventBuilder;
import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response.Status;
/**
@@ -41,6 +46,8 @@ import javax.ws.rs.core.Response.Status;
public class ProtectionService {
private final AuthorizationProvider authorization;
+ @Context
+ protected ClientConnection clientConnection;
public ProtectionService(AuthorizationProvider authorization) {
this.authorization = authorization;
@@ -50,7 +57,12 @@ public class ProtectionService {
public Object resource() {
KeycloakIdentity identity = createIdentity();
ResourceServer resourceServer = getResourceServer(identity);
- ResourceSetService resourceManager = new ResourceSetService(resourceServer, this.authorization, null);
+ RealmModel realm = authorization.getRealm();
+ ClientModel client = realm.getClientById(identity.getId());
+ KeycloakSession keycloakSession = authorization.getKeycloakSession();
+ UserModel serviceAccount = keycloakSession.users().getServiceAccount(client);
+ AdminEventBuilder adminEvent = new AdminEventBuilder(realm, new AdminAuth(realm, identity.getAccessToken(), serviceAccount, client), keycloakSession, clientConnection);
+ ResourceSetService resourceManager = new ResourceSetService(resourceServer, this.authorization, null, adminEvent.realm(realm).authClient(client).authUser(serviceAccount));
ResteasyProviderFactory.getInstance().injectProperties(resourceManager);
diff --git a/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java b/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java
index 1695ba5..c2e11dc 100644
--- a/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java
+++ b/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java
@@ -31,8 +31,10 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.admin.ResourceSetService;
@@ -68,10 +70,10 @@ public class ResourceService {
@POST
@Consumes("application/json")
@Produces("application/json")
- public Response create(UmaResourceRepresentation umaResource) {
+ public Response create(@Context UriInfo uriInfo, UmaResourceRepresentation umaResource) {
checkResourceServerSettings();
ResourceRepresentation resource = toResourceRepresentation(umaResource);
- Response response = this.resourceManager.create(resource);
+ Response response = this.resourceManager.create(uriInfo, resource);
if (response.getEntity() instanceof ResourceRepresentation) {
return Response.status(Status.CREATED).entity(toUmaRepresentation((ResourceRepresentation) response.getEntity())).build();
@@ -84,9 +86,9 @@ public class ResourceService {
@PUT
@Consumes("application/json")
@Produces("application/json")
- public Response update(@PathParam("id") String id, UmaResourceRepresentation representation) {
+ public Response update(@Context UriInfo uriInfo, @PathParam("id") String id, UmaResourceRepresentation representation) {
ResourceRepresentation resource = toResourceRepresentation(representation);
- Response response = this.resourceManager.update(id, resource);
+ Response response = this.resourceManager.update(uriInfo, id, resource);
if (response.getEntity() instanceof ResourceRepresentation) {
return Response.noContent().build();
@@ -97,9 +99,9 @@ public class ResourceService {
@Path("/{id}")
@DELETE
- public Response delete(@PathParam("id") String id) {
+ public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
checkResourceServerSettings();
- return this.resourceManager.delete(id);
+ return this.resourceManager.delete(uriInfo, id);
}
@Path("/{id}")
diff --git a/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java b/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java
index 8f2e153..facce6c 100755
--- a/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java
+++ b/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java
@@ -343,7 +343,7 @@ public class ExportUtils {
representation.setPolicies(policies);
List<ScopeRepresentation> scopes = storeFactory.getScopeStore().findByResourceServer(settingsModel.getId()).stream().map(scope -> {
- ScopeRepresentation rep = toRepresentation(scope, authorization);
+ ScopeRepresentation rep = toRepresentation(scope);
rep.setId(null);
rep.setPolicies(null);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/installation/KeycloakOIDCClientInstallation.java b/services/src/main/java/org/keycloak/protocol/oidc/installation/KeycloakOIDCClientInstallation.java
index dfae565..4fc73f7 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/installation/KeycloakOIDCClientInstallation.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/installation/KeycloakOIDCClientInstallation.java
@@ -151,7 +151,7 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
}
private void configureAuthorizationSettings(KeycloakSession session, ClientModel client, ClientManager.InstallationAdapterConfig rep) {
- if (new AuthorizationService(session, client, null).isEnabled()) {
+ if (new AuthorizationService(session, client, null, null).isEnabled()) {
PolicyEnforcerConfig enforcerConfig = new PolicyEnforcerConfig();
enforcerConfig.setEnforcementMode(null);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index a92729e..43c897c 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -148,36 +148,13 @@ public class ClientResource {
try {
updateClientFromRep(rep, client, session);
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
+ updateAuthorizationSettings(rep);
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
}
}
- public void updateClientFromRep(ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException {
- if (TRUE.equals(rep.isServiceAccountsEnabled())) {
- UserModel serviceAccount = this.session.users().getServiceAccount(client);
-
- if (serviceAccount == null) {
- new ClientManager(new RealmManager(session)).enableServiceAccount(client);
- }
- }
-
- if (!rep.getClientId().equals(client.getClientId())) {
- new ClientManager(new RealmManager(session)).clientIdChanged(client, rep.getClientId());
- }
-
- RepresentationToModel.updateClient(rep, client);
-
- if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
- if (TRUE.equals(rep.getAuthorizationServicesEnabled())) {
- authorization().enable();
- } else {
- authorization().disable();
- }
- }
- }
-
/**
* Get representation of the client
*
@@ -587,10 +564,36 @@ public class ClientResource {
public AuthorizationService authorization() {
ProfileHelper.requireFeature(Profile.Feature.AUTHORIZATION);
- AuthorizationService resource = new AuthorizationService(this.session, this.client, this.auth);
+ AuthorizationService resource = new AuthorizationService(this.session, this.client, this.auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(resource);
return resource;
}
+
+ private void updateClientFromRep(ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException {
+ if (TRUE.equals(rep.isServiceAccountsEnabled())) {
+ UserModel serviceAccount = this.session.users().getServiceAccount(client);
+
+ if (serviceAccount == null) {
+ new ClientManager(new RealmManager(session)).enableServiceAccount(client);
+ }
+ }
+
+ if (!rep.getClientId().equals(client.getClientId())) {
+ new ClientManager(new RealmManager(session)).clientIdChanged(client, rep.getClientId());
+ }
+
+ RepresentationToModel.updateClient(rep, client);
+ }
+
+ private void updateAuthorizationSettings(ClientRepresentation rep) {
+ if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
+ if (TRUE.equals(rep.getAuthorizationServicesEnabled())) {
+ authorization().enable(false);
+ } else {
+ authorization().disable();
+ }
+ }
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
index 3fa3c75..a488ba3 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
@@ -129,7 +129,7 @@ public class ClientsResource {
}
private AuthorizationService getAuthorizationService(ClientModel clientModel) {
- return new AuthorizationService(session, clientModel, auth);
+ return new AuthorizationService(session, clientModel, auth, adminEvent);
}
/**
@@ -167,14 +167,14 @@ public class ClientsResource {
}
}
+ adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, clientModel.getId()).representation(rep).success();
+
if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
if (TRUE.equals(rep.getAuthorizationServicesEnabled())) {
- getAuthorizationService(clientModel).enable();
+ getAuthorizationService(clientModel).enable(true);
}
}
- adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, clientModel.getId()).representation(rep).success();
-
return Response.created(uriInfo.getAbsolutePathBuilder().path(clientModel.getId()).build()).build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
index 244323b..ae122f6 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
@@ -107,7 +107,9 @@ public abstract class AbstractClientTest extends AbstractAuthTest {
clientRep.setPublicClient(Boolean.FALSE);
clientRep.setAuthorizationServicesEnabled(Boolean.TRUE);
clientRep.setServiceAccountsEnabled(Boolean.TRUE);
- return createClient(clientRep);
+ String id = createClient(clientRep);
+ assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientResourcePath(id), ResourceType.AUTHORIZATION_RESOURCE_SERVER);
+ return id;
}
protected ClientRepresentation createOidcClientRep(String name) {