Merge pull request #4214 from pedroigor/KEYCLOAK-4904

[KEYCLOAK-4904] - Authorization Audit - Part 1
This commit is contained in:
Pedro Igor 2017-06-09 17:17:30 -03:00 committed by GitHub
commit fd8a3dccaf
18 changed files with 254 additions and 95 deletions

View file

@ -156,5 +156,25 @@ public enum ResourceType {
/** /**
* *
*/ */
, COMPONENT; , COMPONENT
/**
*
*/
, AUTHORIZATION_RESOURCE_SERVER
/**
*
*/
, AUTHORIZATION_RESOURCE
/**
*
*/
, AUTHORIZATION_SCOPE
/**
*
*/
, AUTHORIZATION_POLICY;
} }

View file

@ -772,11 +772,7 @@ public class ModelToRepresentation {
return rep; return rep;
} }
public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider) { public static ScopeRepresentation toRepresentation(Scope model) {
return toRepresentation(model, authorizationProvider, true);
}
public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider, boolean deep) {
ScopeRepresentation scope = new ScopeRepresentation(); ScopeRepresentation scope = new ScopeRepresentation();
scope.setId(model.getId()); scope.setId(model.getId());

View file

@ -23,6 +23,7 @@ import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@ -34,14 +35,14 @@ public class AuthorizationService {
private final RealmAuth auth; private final RealmAuth auth;
private final ClientModel client; private final ClientModel client;
private final KeycloakSession session;
private final ResourceServer resourceServer; private final ResourceServer resourceServer;
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
private final AdminEventBuilder adminEvent;
public AuthorizationService(KeycloakSession session, ClientModel client, RealmAuth auth) { public AuthorizationService(KeycloakSession session, ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
this.session = session;
this.client = client; this.client = client;
this.authorization = session.getProvider(AuthorizationProvider.class); this.authorization = session.getProvider(AuthorizationProvider.class);
this.adminEvent = adminEvent;
this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().findByClient(this.client.getId()); this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().findByClient(this.client.getId());
this.auth = auth; this.auth = auth;
@ -52,16 +53,16 @@ public class AuthorizationService {
@Path("/resource-server") @Path("/resource-server")
public ResourceServerService resourceServer() { 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); ResteasyProviderFactory.getInstance().injectProperties(resource);
return resource; return resource;
} }
public void enable() { public void enable(boolean newClient) {
if (!isEnabled()) { if (!isEnabled()) {
resourceServer().create(); resourceServer().create(newClient);
} }
} }

View file

@ -22,6 +22,7 @@ import java.util.Map;
import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
/** /**
@ -29,18 +30,18 @@ import org.keycloak.services.resources.admin.RealmAuth;
*/ */
public class PermissionService extends PolicyService { public class PermissionService extends PolicyService {
public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
super(resourceServer, authorization, auth); super(resourceServer, authorization, auth, adminEvent);
} }
@Override @Override
protected PolicyResourceService doCreatePolicyResource(Policy policy) { protected PolicyResourceService doCreatePolicyResource(Policy policy) {
return new PolicyTypeResourceService(policy, resourceServer, authorization, auth); return new PolicyTypeResourceService(policy, resourceServer, authorization, auth, adminEvent);
} }
@Override @Override
protected PolicyTypeService doCreatePolicyTypeResource(String type) { protected PolicyTypeService doCreatePolicyTypeResource(String type) {
return new PolicyTypeService(type, resourceServer, authorization, auth) { return new PolicyTypeService(type, resourceServer, authorization, auth, adminEvent) {
@Override @Override
protected List<Object> doSearch(Integer firstResult, Integer maxResult, Map<String, String[]> filters) { protected List<Object> doSearch(Integer firstResult, Integer maxResult, Map<String, String[]> filters) {
filters.put("permission", new String[] {Boolean.TRUE.toString()}); filters.put("permission", new String[] {Boolean.TRUE.toString()});

View file

@ -26,8 +26,10 @@ import javax.ws.rs.GET;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.authorization.AuthorizationProvider; 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.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.PolicyStore; import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory; 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.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation; import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -54,19 +59,21 @@ public class PolicyResourceService {
protected final ResourceServer resourceServer; protected final ResourceServer resourceServer;
protected final AuthorizationProvider authorization; protected final AuthorizationProvider authorization;
protected final RealmAuth auth; 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.policy = policy;
this.resourceServer = resourceServer; this.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
this.auth = auth; this.auth = auth;
this.adminEvent = adminEvent.resource(ResourceType.AUTHORIZATION_POLICY);
} }
@PUT @PUT
@Consumes("application/json") @Consumes("application/json")
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response update(String payload) { public Response update(@Context UriInfo uriInfo, String payload) {
this.auth.requireManage(); this.auth.requireManage();
AbstractPolicyRepresentation representation = doCreateRepresentation(payload); AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
@ -79,11 +86,14 @@ public class PolicyResourceService {
RepresentationToModel.toModel(representation, authorization, policy); RepresentationToModel.toModel(representation, authorization, policy);
audit(uriInfo, representation, OperationType.UPDATE);
return Response.status(Status.CREATED).build(); return Response.status(Status.CREATED).build();
} }
@DELETE @DELETE
public Response delete() { public Response delete(@Context UriInfo uriInfo) {
this.auth.requireManage(); this.auth.requireManage();
if (policy == null) { if (policy == null) {
@ -98,6 +108,10 @@ public class PolicyResourceService {
policyStore.delete(policy.getId()); policyStore.delete(policy.getId());
if (authorization.getRealm().isAdminEventsEnabled()) {
audit(uriInfo, toRepresentation(policy, authorization), OperationType.DELETE);
}
return Response.noContent().build(); return Response.noContent().build();
} }
@ -225,4 +239,10 @@ public class PolicyResourceService {
protected Policy getPolicy() { protected Policy getPolicy() {
return policy; return policy;
} }
private void audit(@Context UriInfo uriInfo, AbstractPolicyRepresentation policy, OperationType operation) {
if (authorization.getRealm().isAdminEventsEnabled()) {
adminEvent.operation(operation).resourcePath(uriInfo).representation(policy).success();
}
}
} }

View file

@ -33,9 +33,11 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.ResteasyProviderFactory; 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.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.PolicyStore; import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory; 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.Constants;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyProviderRepresentation; import org.keycloak.representations.idm.authorization.PolicyProviderRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -63,11 +69,13 @@ public class PolicyService {
protected final ResourceServer resourceServer; protected final ResourceServer resourceServer;
protected final AuthorizationProvider authorization; protected final AuthorizationProvider authorization;
protected final RealmAuth auth; 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.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
this.auth = auth; this.auth = auth;
this.adminEvent = adminEvent.resource(ResourceType.AUTHORIZATION_POLICY);
} }
@Path("{type}") @Path("{type}")
@ -84,18 +92,18 @@ public class PolicyService {
} }
protected PolicyTypeService doCreatePolicyTypeResource(String type) { 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) { protected Object doCreatePolicyResource(Policy policy) {
return new PolicyResourceService(policy, resourceServer, authorization, auth); return new PolicyResourceService(policy, resourceServer, authorization, auth, adminEvent);
} }
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public Response create(String payload) { public Response create(@Context UriInfo uriInfo, String payload) {
this.auth.requireManage(); this.auth.requireManage();
AbstractPolicyRepresentation representation = doCreateRepresentation(payload); AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
@ -103,6 +111,8 @@ public class PolicyService {
representation.setId(policy.getId()); representation.setId(policy.getId());
audit(uriInfo, representation, representation.getId(), OperationType.CREATE);
return Response.status(Status.CREATED).entity(representation).build(); return Response.status(Status.CREATED).entity(representation).build();
} }
@ -280,4 +290,14 @@ public class PolicyService {
findAssociatedPolicies(associated, policies); 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();
}
}
}
} }

View file

@ -24,6 +24,7 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory; import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -32,8 +33,8 @@ import org.keycloak.util.JsonSerialization;
*/ */
public class PolicyTypeResourceService extends PolicyResourceService { public class PolicyTypeResourceService extends PolicyResourceService {
public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
super(policy, resourceServer, authorization, auth); super(policy, resourceServer, authorization, auth, adminEvent);
} }
@Override @Override

View file

@ -30,6 +30,7 @@ import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory; import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -40,8 +41,8 @@ public class PolicyTypeService extends PolicyService {
private final String type; private final String type;
PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
super(resourceServer, authorization, auth); super(resourceServer, authorization, auth, adminEvent);
this.type = type; this.type = type;
} }
@ -60,7 +61,7 @@ public class PolicyTypeService extends PolicyService {
@Override @Override
protected Object doCreatePolicyResource(Policy policy) { protected Object doCreatePolicyResource(Policy policy) {
return new PolicyTypeResourceService(policy, resourceServer,authorization, auth); return new PolicyTypeResourceService(policy, resourceServer,authorization, auth, adminEvent);
} }
@Override @Override

View file

@ -40,12 +40,15 @@ import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceStore; import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.ScopeStore; import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory; 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.exportimport.util.ExportUtils;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.authorization.DecisionStrategy; import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic; 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.ResourcePermissionRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
/** /**
@ -62,19 +66,24 @@ public class ResourceServerService {
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
private final RealmAuth auth; private final RealmAuth auth;
private final AdminEventBuilder adminEvent;
private final KeycloakSession session; private final KeycloakSession session;
private ResourceServer resourceServer; private ResourceServer resourceServer;
private final ClientModel client; 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.authorization = authorization;
this.session = authorization.getKeycloakSession(); this.session = authorization.getKeycloakSession();
this.client = client; this.client = client;
this.resourceServer = resourceServer; this.resourceServer = resourceServer;
this.auth = auth; this.auth = auth;
this.adminEvent = adminEvent;
} }
public void create() { public void create(boolean newClient) {
this.auth.requireManage(); this.auth.requireManage();
UserModel serviceAccount = this.session.users().getServiceAccount(client); UserModel serviceAccount = this.session.users().getServiceAccount(client);
@ -86,16 +95,17 @@ public class ResourceServerService {
this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().create(this.client.getId()); this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().create(this.client.getId());
createDefaultRoles(serviceAccount); createDefaultRoles(serviceAccount);
createDefaultPermission(createDefaultResource(), createDefaultPolicy()); createDefaultPermission(createDefaultResource(), createDefaultPolicy());
audit(OperationType.CREATE, uriInfo, newClient);
} }
@PUT @PUT
@Consumes("application/json") @Consumes("application/json")
@Produces("application/json") @Produces("application/json")
public Response update(ResourceServerRepresentation server) { public Response update(@Context UriInfo uriInfo, ResourceServerRepresentation server) {
this.auth.requireManage(); this.auth.requireManage();
this.resourceServer.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement()); this.resourceServer.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement());
this.resourceServer.setPolicyEnforcementMode(server.getPolicyEnforcementMode()); this.resourceServer.setPolicyEnforcementMode(server.getPolicyEnforcementMode());
audit(OperationType.UPDATE, uriInfo, false);
return Response.noContent().build(); return Response.noContent().build();
} }
@ -105,17 +115,19 @@ public class ResourceServerService {
ResourceStore resourceStore = storeFactory.getResourceStore(); ResourceStore resourceStore = storeFactory.getResourceStore();
String id = resourceServer.getId(); 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())); resourceStore.findByResourceServer(id).forEach(resource -> resourceStore.delete(resource.getId()));
ScopeStore scopeStore = storeFactory.getScopeStore(); ScopeStore scopeStore = storeFactory.getScopeStore();
scopeStore.findByResourceServer(id).forEach(scope -> scopeStore.delete(scope.getId())); 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); storeFactory.getResourceServerStore().delete(id);
audit(OperationType.DELETE, uriInfo, false);
} }
@GET @GET
@ -143,12 +155,14 @@ public class ResourceServerService {
RepresentationToModel.toModel(rep, authorization); RepresentationToModel.toModel(rep, authorization);
audit(OperationType.UPDATE, uriInfo, false);
return Response.noContent().build(); return Response.noContent().build();
} }
@Path("/resource") @Path("/resource")
public ResourceSetService getResourceSetResource() { 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); ResteasyProviderFactory.getInstance().injectProperties(resource);
@ -157,7 +171,7 @@ public class ResourceServerService {
@Path("/scope") @Path("/scope")
public ScopeService getScopeResource() { 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); ResteasyProviderFactory.getInstance().injectProperties(resource);
@ -166,7 +180,7 @@ public class ResourceServerService {
@Path("/policy") @Path("/policy")
public PolicyService getPolicyResource() { 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); ResteasyProviderFactory.getInstance().injectProperties(resource);
@ -176,7 +190,7 @@ public class ResourceServerService {
@Path("/permission") @Path("/permission")
public Object getPermissionTypeResource() { public Object getPermissionTypeResource() {
this.auth.requireView(); 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); ResteasyProviderFactory.getInstance().injectProperties(resource);
@ -239,4 +253,14 @@ public class ResourceServerService {
serviceAccount.grantRole(umaProtectionRole); 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();
}
}
} }

View file

@ -26,6 +26,8 @@ import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.PolicyStore; import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceStore; import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.StoreFactory; 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.ClientModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; 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.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation; import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -48,8 +51,10 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -70,17 +75,25 @@ public class ResourceSetService {
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
private final RealmAuth auth; private final RealmAuth auth;
private final AdminEventBuilder adminEvent;
private ResourceServer resourceServer; 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.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
this.auth = auth; this.auth = auth;
this.adminEvent = adminEvent.resource(ResourceType.AUTHORIZATION_RESOURCE);
} }
@POST @POST
@Consumes("application/json") @Consumes("application/json")
@Produces("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) { public Response create(ResourceRepresentation resource) {
requireManage(); requireManage();
StoreFactory storeFactory = this.authorization.getStoreFactory(); StoreFactory storeFactory = this.authorization.getStoreFactory();
@ -128,7 +141,7 @@ public class ResourceSetService {
@PUT @PUT
@Consumes("application/json") @Consumes("application/json")
@Produces("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(); requireManage();
resource.setId(id); resource.setId(id);
StoreFactory storeFactory = this.authorization.getStoreFactory(); StoreFactory storeFactory = this.authorization.getStoreFactory();
@ -141,12 +154,14 @@ public class ResourceSetService {
toModel(resource, resourceServer, authorization); toModel(resource, resourceServer, authorization);
audit(uriInfo, resource, OperationType.UPDATE);
return Response.noContent().build(); return Response.noContent().build();
} }
@Path("{id}") @Path("{id}")
@DELETE @DELETE
public Response delete(@PathParam("id") String id) { public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
requireManage(); requireManage();
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
Resource resource = storeFactory.getResourceStore().findById(id, resourceServer.getId()); Resource resource = storeFactory.getResourceStore().findById(id, resourceServer.getId());
@ -168,6 +183,10 @@ public class ResourceSetService {
storeFactory.getResourceStore().delete(id); storeFactory.getResourceStore().delete(id);
if (authorization.getRealm().isAdminEventsEnabled()) {
audit(uriInfo, toRepresentation(resource, resourceServer, authorization), OperationType.DELETE);
}
return Response.noContent().build(); return Response.noContent().build();
} }
@ -376,4 +395,18 @@ public class ResourceSetService {
this.auth.requireManage(); 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();
}
}
}
} }

View file

@ -25,11 +25,14 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope; import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.PolicyStore; import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory; 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.Constants;
import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation; import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.RealmAuth;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -41,9 +44,11 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -61,23 +66,27 @@ public class ScopeService {
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
private final RealmAuth auth; private final RealmAuth auth;
private final AdminEventBuilder adminEvent;
private ResourceServer resourceServer; 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.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
this.auth = auth; this.auth = auth;
this.adminEvent = adminEvent.resource(ResourceType.AUTHORIZATION_SCOPE);
} }
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response create(ScopeRepresentation scope) { public Response create(@Context UriInfo uriInfo, ScopeRepresentation scope) {
this.auth.requireManage(); this.auth.requireManage();
Scope model = toModel(scope, this.resourceServer, authorization); Scope model = toModel(scope, this.resourceServer, authorization);
scope.setId(model.getId()); scope.setId(model.getId());
audit(uriInfo, scope, scope.getId(), OperationType.CREATE);
return Response.status(Status.CREATED).entity(scope).build(); return Response.status(Status.CREATED).entity(scope).build();
} }
@ -85,7 +94,7 @@ public class ScopeService {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(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(); this.auth.requireManage();
scope.setId(id); scope.setId(id);
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
@ -97,12 +106,14 @@ public class ScopeService {
toModel(scope, resourceServer, authorization); toModel(scope, resourceServer, authorization);
audit(uriInfo, scope, OperationType.UPDATE);
return Response.noContent().build(); return Response.noContent().build();
} }
@Path("{id}") @Path("{id}")
@DELETE @DELETE
public Response delete(@PathParam("id") String id) { public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
this.auth.requireManage(); this.auth.requireManage();
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
List<Resource> resources = storeFactory.getResourceStore().findByScope(Arrays.asList(id), resourceServer.getId()); List<Resource> resources = storeFactory.getResourceStore().findByScope(Arrays.asList(id), resourceServer.getId());
@ -130,6 +141,10 @@ public class ScopeService {
storeFactory.getScopeStore().delete(id); storeFactory.getScopeStore().delete(id);
if (authorization.getRealm().isAdminEventsEnabled()) {
audit(uriInfo, toRepresentation(scope), OperationType.DELETE);
}
return Response.noContent().build(); return Response.noContent().build();
} }
@ -144,7 +159,7 @@ public class ScopeService {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
} }
return Response.ok(toRepresentation(model, this.authorization)).build(); return Response.ok(toRepresentation(model)).build();
} }
@Path("{id}/resources") @Path("{id}/resources")
@ -212,22 +227,17 @@ public class ScopeService {
return Response.status(Status.OK).build(); return Response.status(Status.OK).build();
} }
return Response.ok(toRepresentation(model, authorization)).build(); return Response.ok(toRepresentation(model)).build();
} }
@GET @GET
@Produces("application/json") @Produces("application/json")
public Response findAll(@QueryParam("scopeId") String id, public Response findAll(@QueryParam("scopeId") String id,
@QueryParam("name") String name, @QueryParam("name") String name,
@QueryParam("deep") Boolean deep,
@QueryParam("first") Integer firstResult, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResult) { @QueryParam("max") Integer maxResult) {
this.auth.requireView(); this.auth.requireView();
if (deep == null) {
deep = true;
}
Map<String, String[]> search = new HashMap<>(); Map<String, String[]> search = new HashMap<>();
if (id != null && !"".equals(id.trim())) { if (id != null && !"".equals(id.trim())) {
@ -238,11 +248,24 @@ public class ScopeService {
search.put("name", new String[] {name}); search.put("name", new String[] {name});
} }
Boolean finalDeep = deep;
return Response.ok( return Response.ok(
this.authorization.getStoreFactory().getScopeStore().findByResourceServer(search, this.resourceServer.getId(), firstResult != null ? firstResult : -1, maxResult != null ? maxResult : Constants.DEFAULT_MAX_RESULTS).stream() 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())) .collect(Collectors.toList()))
.build(); .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();
}
}
}
} }

View file

@ -27,12 +27,17 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.protection.permission.PermissionService; import org.keycloak.authorization.protection.permission.PermissionService;
import org.keycloak.authorization.protection.permission.PermissionsService; import org.keycloak.authorization.protection.permission.PermissionsService;
import org.keycloak.authorization.protection.resource.ResourceService; import org.keycloak.authorization.protection.resource.ResourceService;
import org.keycloak.common.ClientConnection;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.ErrorResponseException; 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.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
/** /**
@ -41,6 +46,8 @@ import javax.ws.rs.core.Response.Status;
public class ProtectionService { public class ProtectionService {
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
@Context
protected ClientConnection clientConnection;
public ProtectionService(AuthorizationProvider authorization) { public ProtectionService(AuthorizationProvider authorization) {
this.authorization = authorization; this.authorization = authorization;
@ -50,7 +57,12 @@ public class ProtectionService {
public Object resource() { public Object resource() {
KeycloakIdentity identity = createIdentity(); KeycloakIdentity identity = createIdentity();
ResourceServer resourceServer = getResourceServer(identity); 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); ResteasyProviderFactory.getInstance().injectProperties(resourceManager);

View file

@ -31,8 +31,10 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.admin.ResourceSetService; import org.keycloak.authorization.admin.ResourceSetService;
@ -68,10 +70,10 @@ public class ResourceService {
@POST @POST
@Consumes("application/json") @Consumes("application/json")
@Produces("application/json") @Produces("application/json")
public Response create(UmaResourceRepresentation umaResource) { public Response create(@Context UriInfo uriInfo, UmaResourceRepresentation umaResource) {
checkResourceServerSettings(); checkResourceServerSettings();
ResourceRepresentation resource = toResourceRepresentation(umaResource); ResourceRepresentation resource = toResourceRepresentation(umaResource);
Response response = this.resourceManager.create(resource); Response response = this.resourceManager.create(uriInfo, resource);
if (response.getEntity() instanceof ResourceRepresentation) { if (response.getEntity() instanceof ResourceRepresentation) {
return Response.status(Status.CREATED).entity(toUmaRepresentation((ResourceRepresentation) response.getEntity())).build(); return Response.status(Status.CREATED).entity(toUmaRepresentation((ResourceRepresentation) response.getEntity())).build();
@ -84,9 +86,9 @@ public class ResourceService {
@PUT @PUT
@Consumes("application/json") @Consumes("application/json")
@Produces("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); ResourceRepresentation resource = toResourceRepresentation(representation);
Response response = this.resourceManager.update(id, resource); Response response = this.resourceManager.update(uriInfo, id, resource);
if (response.getEntity() instanceof ResourceRepresentation) { if (response.getEntity() instanceof ResourceRepresentation) {
return Response.noContent().build(); return Response.noContent().build();
@ -97,9 +99,9 @@ public class ResourceService {
@Path("/{id}") @Path("/{id}")
@DELETE @DELETE
public Response delete(@PathParam("id") String id) { public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
checkResourceServerSettings(); checkResourceServerSettings();
return this.resourceManager.delete(id); return this.resourceManager.delete(uriInfo, id);
} }
@Path("/{id}") @Path("/{id}")

View file

@ -343,7 +343,7 @@ public class ExportUtils {
representation.setPolicies(policies); representation.setPolicies(policies);
List<ScopeRepresentation> scopes = storeFactory.getScopeStore().findByResourceServer(settingsModel.getId()).stream().map(scope -> { List<ScopeRepresentation> scopes = storeFactory.getScopeStore().findByResourceServer(settingsModel.getId()).stream().map(scope -> {
ScopeRepresentation rep = toRepresentation(scope, authorization); ScopeRepresentation rep = toRepresentation(scope);
rep.setId(null); rep.setId(null);
rep.setPolicies(null); rep.setPolicies(null);

View file

@ -151,7 +151,7 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
} }
private void configureAuthorizationSettings(KeycloakSession session, ClientModel client, ClientManager.InstallationAdapterConfig rep) { 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(); PolicyEnforcerConfig enforcerConfig = new PolicyEnforcerConfig();
enforcerConfig.setEnforcementMode(null); enforcerConfig.setEnforcementMode(null);

View file

@ -148,36 +148,13 @@ public class ClientResource {
try { try {
updateClientFromRep(rep, client, session); updateClientFromRep(rep, client, session);
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success(); adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
updateAuthorizationSettings(rep);
return Response.noContent().build(); return Response.noContent().build();
} catch (ModelDuplicateException e) { } catch (ModelDuplicateException e) {
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists"); 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 * Get representation of the client
* *
@ -587,10 +564,36 @@ public class ClientResource {
public AuthorizationService authorization() { public AuthorizationService authorization() {
ProfileHelper.requireFeature(Profile.Feature.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); ResteasyProviderFactory.getInstance().injectProperties(resource);
return 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();
}
}
}
} }

View file

@ -129,7 +129,7 @@ public class ClientsResource {
} }
private AuthorizationService getAuthorizationService(ClientModel clientModel) { 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 (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
if (TRUE.equals(rep.getAuthorizationServicesEnabled())) { 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(); return Response.created(uriInfo.getAbsolutePathBuilder().path(clientModel.getId()).build()).build();
} catch (ModelDuplicateException e) { } catch (ModelDuplicateException e) {
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists"); return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");

View file

@ -107,7 +107,9 @@ public abstract class AbstractClientTest extends AbstractAuthTest {
clientRep.setPublicClient(Boolean.FALSE); clientRep.setPublicClient(Boolean.FALSE);
clientRep.setAuthorizationServicesEnabled(Boolean.TRUE); clientRep.setAuthorizationServicesEnabled(Boolean.TRUE);
clientRep.setServiceAccountsEnabled(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) { protected ClientRepresentation createOidcClientRep(String name) {