auth changes

This commit is contained in:
Bill Burke 2017-05-29 09:53:17 -04:00
parent ab763e7c5b
commit c3ea847b3e
64 changed files with 3150 additions and 1469 deletions

View file

@ -46,6 +46,10 @@ public interface ClientsResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<ClientRepresentation> findAll(); public List<ClientRepresentation> findAll();
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<ClientRepresentation> findAll(@QueryParam("viewableOnly") boolean viewableOnly);
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<ClientRepresentation> findByClientId(@QueryParam("clientId") String clientId); public List<ClientRepresentation> findByClientId(@QueryParam("clientId") String clientId);

View file

@ -23,7 +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.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@ -32,22 +32,18 @@ import javax.ws.rs.Path;
*/ */
public class AuthorizationService { public class AuthorizationService {
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
private final ClientModel client; private final ClientModel client;
private final KeycloakSession session; private final KeycloakSession session;
private final ResourceServer resourceServer; private final ResourceServer resourceServer;
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
public AuthorizationService(KeycloakSession session, ClientModel client, RealmAuth auth) { public AuthorizationService(KeycloakSession session, ClientModel client, AdminPermissionEvaluator auth) {
this.session = session; this.session = session;
this.client = client; this.client = client;
this.authorization = session.getProvider(AuthorizationProvider.class); this.authorization = session.getProvider(AuthorizationProvider.class);
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;
if (auth != null) {
this.auth.init(RealmAuth.Resource.AUTHORIZATION);
}
} }
@Path("/resource-server") @Path("/resource-server")

View file

@ -22,14 +22,14 @@ 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.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
public class PermissionService extends PolicyService { public class PermissionService extends PolicyService {
public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth) {
super(resourceServer, authorization, auth); super(resourceServer, authorization, auth);
} }

View file

@ -63,14 +63,12 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.ProtocolMapper;
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
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.Urls; import org.keycloak.services.Urls;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.AuthenticationSessionModel;
/** /**
@ -79,13 +77,13 @@ import org.keycloak.sessions.AuthenticationSessionModel;
public class PolicyEvaluationService { public class PolicyEvaluationService {
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
@Context @Context
private HttpRequest httpRequest; private HttpRequest httpRequest;
private final ResourceServer resourceServer; private final ResourceServer resourceServer;
PolicyEvaluationService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { PolicyEvaluationService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth) {
this.resourceServer = resourceServer; this.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
this.auth = auth; this.auth = auth;
@ -117,7 +115,7 @@ public class PolicyEvaluationService {
@Consumes("application/json") @Consumes("application/json")
@Produces("application/json") @Produces("application/json")
public Response evaluate(PolicyEvaluationRequest evaluationRequest) throws Throwable { public Response evaluate(PolicyEvaluationRequest evaluationRequest) throws Throwable {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
CloseableKeycloakIdentity identity = createIdentity(evaluationRequest); CloseableKeycloakIdentity identity = createIdentity(evaluationRequest);
try { try {
EvaluationContext evaluationContext = createEvaluationContext(evaluationRequest, identity); EvaluationContext evaluationContext = createEvaluationContext(evaluationRequest, identity);

View file

@ -42,7 +42,7 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati
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.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
/** /**
@ -53,9 +53,9 @@ public class PolicyResourceService {
private final Policy policy; private final Policy policy;
protected final ResourceServer resourceServer; protected final ResourceServer resourceServer;
protected final AuthorizationProvider authorization; protected final AuthorizationProvider authorization;
protected final RealmAuth auth; protected final AdminPermissionEvaluator auth;
public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth) {
this.policy = policy; this.policy = policy;
this.resourceServer = resourceServer; this.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
@ -67,7 +67,7 @@ public class PolicyResourceService {
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response update(String payload) { public Response update(String payload) {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
AbstractPolicyRepresentation representation = doCreateRepresentation(payload); AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
@ -84,7 +84,7 @@ public class PolicyResourceService {
@DELETE @DELETE
public Response delete() { public Response delete() {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
if (policy == null) { if (policy == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
@ -105,7 +105,7 @@ public class PolicyResourceService {
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response findById() { public Response findById() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
if (policy == null) { if (policy == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
@ -123,7 +123,7 @@ public class PolicyResourceService {
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response getDependentPolicies() { public Response getDependentPolicies() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
if (policy == null) { if (policy == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
@ -147,7 +147,7 @@ public class PolicyResourceService {
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response getScopes() { public Response getScopes() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
if (policy == null) { if (policy == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
@ -168,7 +168,7 @@ public class PolicyResourceService {
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response getResources() { public Response getResources() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
if (policy == null) { if (policy == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
@ -189,7 +189,7 @@ public class PolicyResourceService {
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response getAssociatedPolicies() { public Response getAssociatedPolicies() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
if (policy == null) { if (policy == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();

View file

@ -52,7 +52,7 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati
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.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
/** /**
@ -62,9 +62,9 @@ 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 AdminPermissionEvaluator auth;
public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth) {
this.resourceServer = resourceServer; this.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
this.auth = auth; this.auth = auth;
@ -92,7 +92,7 @@ public class PolicyService {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public Response create(String payload) { public Response create(String payload) {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
AbstractPolicyRepresentation representation = doCreateRepresentation(payload); AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
Policy policy = create(representation); Policy policy = create(representation);
@ -130,7 +130,7 @@ public class PolicyService {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public Response findByName(@QueryParam("name") String name) { public Response findByName(@QueryParam("name") String name) {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
if (name == null) { if (name == null) {
@ -157,7 +157,7 @@ public class PolicyService {
@QueryParam("permission") Boolean permission, @QueryParam("permission") Boolean permission,
@QueryParam("first") Integer firstResult, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResult) { @QueryParam("max") Integer maxResult) {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
Map<String, String[]> search = new HashMap<>(); Map<String, String[]> search = new HashMap<>();
@ -236,7 +236,7 @@ public class PolicyService {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public Response findPolicyProviders() { public Response findPolicyProviders() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
return Response.ok( return Response.ok(
authorization.getProviderFactories().stream() authorization.getProviderFactories().stream()
.map(provider -> { .map(provider -> {
@ -254,7 +254,7 @@ public class PolicyService {
@Path("evaluate") @Path("evaluate")
public PolicyEvaluationService getPolicyEvaluateResource() { public PolicyEvaluationService getPolicyEvaluateResource() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
PolicyEvaluationService resource = new PolicyEvaluationService(this.resourceServer, this.authorization, this.auth); PolicyEvaluationService resource = new PolicyEvaluationService(this.resourceServer, this.authorization, this.auth);
ResteasyProviderFactory.getInstance().injectProperties(resource); ResteasyProviderFactory.getInstance().injectProperties(resource);

View file

@ -24,7 +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.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
/** /**
@ -32,7 +32,7 @@ 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, AdminPermissionEvaluator auth) {
super(policy, resourceServer, authorization, auth); super(policy, resourceServer, authorization, auth);
} }

View file

@ -28,7 +28,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.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
/** /**
@ -38,7 +38,7 @@ 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, AdminPermissionEvaluator auth) {
super(resourceServer, authorization, auth); super(resourceServer, authorization, auth);
this.type = type; this.type = type;
} }

View file

@ -53,7 +53,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.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -61,12 +61,12 @@ import org.keycloak.services.resources.admin.RealmAuth;
public class ResourceServerService { public class ResourceServerService {
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
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) { public ResourceServerService(AuthorizationProvider authorization, ResourceServer resourceServer, ClientModel client, AdminPermissionEvaluator auth) {
this.authorization = authorization; this.authorization = authorization;
this.session = authorization.getKeycloakSession(); this.session = authorization.getKeycloakSession();
this.client = client; this.client = client;
@ -75,7 +75,7 @@ public class ResourceServerService {
} }
public void create() { public void create() {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
UserModel serviceAccount = this.session.users().getServiceAccount(client); UserModel serviceAccount = this.session.users().getServiceAccount(client);
@ -92,7 +92,7 @@ public class ResourceServerService {
@Consumes("application/json") @Consumes("application/json")
@Produces("application/json") @Produces("application/json")
public Response update(ResourceServerRepresentation server) { public Response update(ResourceServerRepresentation server) {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
this.resourceServer.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement()); this.resourceServer.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement());
this.resourceServer.setPolicyEnforcementMode(server.getPolicyEnforcementMode()); this.resourceServer.setPolicyEnforcementMode(server.getPolicyEnforcementMode());
@ -100,7 +100,7 @@ public class ResourceServerService {
} }
public void delete() { public void delete() {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
ResourceStore resourceStore = storeFactory.getResourceStore(); ResourceStore resourceStore = storeFactory.getResourceStore();
String id = resourceServer.getId(); String id = resourceServer.getId();
@ -121,7 +121,7 @@ public class ResourceServerService {
@GET @GET
@Produces("application/json") @Produces("application/json")
public Response findById() { public Response findById() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
return Response.ok(toRepresentation(this.resourceServer, this.client)).build(); return Response.ok(toRepresentation(this.resourceServer, this.client)).build();
} }
@ -129,7 +129,7 @@ public class ResourceServerService {
@GET @GET
@Produces("application/json") @Produces("application/json")
public Response exportSettings() { public Response exportSettings() {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
return Response.ok(ExportUtils.exportAuthorizationSettings(session, client)).build(); return Response.ok(ExportUtils.exportAuthorizationSettings(session, client)).build();
} }
@ -137,7 +137,7 @@ public class ResourceServerService {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response importSettings(@Context final UriInfo uriInfo, ResourceServerRepresentation rep) throws IOException { public Response importSettings(@Context final UriInfo uriInfo, ResourceServerRepresentation rep) throws IOException {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
rep.setClientId(client.getId()); rep.setClientId(client.getId());
@ -175,7 +175,7 @@ public class ResourceServerService {
@Path("/permission") @Path("/permission")
public Object getPermissionTypeResource() { public Object getPermissionTypeResource() {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
PermissionService resource = new PermissionService(this.resourceServer, this.authorization, this.auth); PermissionService resource = new PermissionService(this.resourceServer, this.authorization, this.auth);
ResteasyProviderFactory.getInstance().injectProperties(resource); ResteasyProviderFactory.getInstance().injectProperties(resource);

View file

@ -37,7 +37,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.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -69,10 +69,10 @@ import static org.keycloak.models.utils.RepresentationToModel.toModel;
public class ResourceSetService { public class ResourceSetService {
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
private ResourceServer resourceServer; private ResourceServer resourceServer;
public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth) {
this.resourceServer = resourceServer; this.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
this.auth = auth; this.auth = auth;
@ -272,7 +272,7 @@ public class ResourceSetService {
@Produces("application/json") @Produces("application/json")
@NoCache @NoCache
public Response find(@QueryParam("name") String name) { public Response find(@QueryParam("name") String name) {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
if (name == null) { if (name == null) {
@ -367,13 +367,13 @@ public class ResourceSetService {
private void requireView() { private void requireView() {
if (this.auth != null) { if (this.auth != null) {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
} }
} }
private void requireManage() { private void requireManage() {
if (this.auth != null) { if (this.auth != null) {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
} }
} }
} }

View file

@ -30,7 +30,7 @@ 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.RealmAuth; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -60,10 +60,10 @@ import static org.keycloak.models.utils.RepresentationToModel.toModel;
public class ScopeService { public class ScopeService {
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
private ResourceServer resourceServer; private ResourceServer resourceServer;
public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) { public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth) {
this.resourceServer = resourceServer; this.resourceServer = resourceServer;
this.authorization = authorization; this.authorization = authorization;
this.auth = auth; this.auth = auth;
@ -73,7 +73,7 @@ public class ScopeService {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response create(ScopeRepresentation scope) { public Response create(ScopeRepresentation scope) {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
Scope model = toModel(scope, this.resourceServer, authorization); Scope model = toModel(scope, this.resourceServer, authorization);
scope.setId(model.getId()); scope.setId(model.getId());
@ -86,7 +86,7 @@ public class ScopeService {
@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(@PathParam("id") String id, ScopeRepresentation scope) {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
scope.setId(id); scope.setId(id);
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
Scope model = storeFactory.getScopeStore().findById(scope.getId(), resourceServer.getId()); Scope model = storeFactory.getScopeStore().findById(scope.getId(), resourceServer.getId());
@ -103,7 +103,7 @@ public class ScopeService {
@Path("{id}") @Path("{id}")
@DELETE @DELETE
public Response delete(@PathParam("id") String id) { public Response delete(@PathParam("id") String id) {
this.auth.requireManage(); this.auth.realm().requireManageAuthorization();
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());
@ -137,7 +137,7 @@ public class ScopeService {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response findById(@PathParam("id") String id) { public Response findById(@PathParam("id") String id) {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
Scope model = this.authorization.getStoreFactory().getScopeStore().findById(id, resourceServer.getId()); Scope model = this.authorization.getStoreFactory().getScopeStore().findById(id, resourceServer.getId());
if (model == null) { if (model == null) {
@ -151,7 +151,7 @@ public class ScopeService {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response getResources(@PathParam("id") String id) { public Response getResources(@PathParam("id") String id) {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
StoreFactory storeFactory = this.authorization.getStoreFactory(); StoreFactory storeFactory = this.authorization.getStoreFactory();
Scope model = storeFactory.getScopeStore().findById(id, resourceServer.getId()); Scope model = storeFactory.getScopeStore().findById(id, resourceServer.getId());
@ -173,7 +173,7 @@ public class ScopeService {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response getPermissions(@PathParam("id") String id) { public Response getPermissions(@PathParam("id") String id) {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
StoreFactory storeFactory = this.authorization.getStoreFactory(); StoreFactory storeFactory = this.authorization.getStoreFactory();
Scope model = storeFactory.getScopeStore().findById(id, resourceServer.getId()); Scope model = storeFactory.getScopeStore().findById(id, resourceServer.getId());
@ -199,7 +199,7 @@ public class ScopeService {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public Response find(@QueryParam("name") String name) { public Response find(@QueryParam("name") String name) {
this.auth.requireView(); this.auth.realm().requireViewAuthorization();
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
if (name == null) { if (name == null) {
@ -222,7 +222,7 @@ public class ScopeService {
@QueryParam("deep") Boolean deep, @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.realm().requireViewAuthorization();
if (deep == null) { if (deep == null) {
deep = true; deep = true;

View file

@ -1,118 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.admin.permissions;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.AuthorizationProviderFactory;
import org.keycloak.authorization.common.KeycloakIdentity;
import org.keycloak.authorization.common.UserModelIdentity;
import org.keycloak.authorization.identity.Identity;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.admin.AdminAuth;
import org.keycloak.services.resources.admin.RealmAuth;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MgmtPermissions {
public static final String MANAGE_SCOPE = "manage";
protected RealmModel realm;
protected KeycloakSession session;
protected AuthorizationProvider authz;
protected AdminAuth auth;
protected Identity identity;
public MgmtPermissions(KeycloakSession session, RealmModel realm) {
this.session = session;
this.realm = realm;
KeycloakSessionFactory keycloakSessionFactory = session.getKeycloakSessionFactory();
AuthorizationProviderFactory factory = (AuthorizationProviderFactory) keycloakSessionFactory.getProviderFactory(AuthorizationProvider.class);
this.authz = factory.create(session, realm);
}
public MgmtPermissions(KeycloakSession session, RealmModel realm, AdminAuth auth) {
this(session, realm);
this.auth = auth;
}
public ClientModel getRealmManagementClient() {
ClientModel client = null;
if (realm.getName().equals(Config.getAdminRealm())) {
client = realm.getClientByClientId(Config.getAdminRealm() + "-realm");
} else {
client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
}
return client;
}
public boolean isAdminSameRealm() {
return auth == null || realm.getId().equals(auth.getRealm().getId());
}
public RealmAuth getRealmAuth() {
if (auth == null) return null;
RealmManager realmManager = new RealmManager(session);
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
return new RealmAuth(auth, realm.getMasterAdminClient());
} else {
return new RealmAuth(auth, realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())));
}
}
public Identity identity() {
if (identity != null) return identity;
if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)) {
this.identity = new UserModelIdentity(realm, auth.getUser());
} else {
this.identity = new KeycloakIdentity(auth.getToken(), session);
}
return this.identity;
}
public void setIdentity(UserModel user) {
this.identity = new UserModelIdentity(realm, user);
}
public RoleMgmtPermissions roles() {
return new RoleMgmtPermissions(session, realm, authz, this);
}
public UsersPermissions users() { return new UsersPermissions(session, realm, authz, this); }
public ResourceServer findOrCreateResourceServer(ClientModel client) {
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) {
server = authz.getStoreFactory().getResourceServerStore().create(client.getId());
}
return server;
}
}

View file

@ -1,208 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.admin.permissions;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.Decision;
import org.keycloak.authorization.common.DefaultEvaluationContext;
import org.keycloak.authorization.identity.Identity;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.permission.ResourcePermission;
import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
import org.keycloak.authorization.policy.evaluation.DecisionResult;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.util.Permissions;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RoleMgmtPermissions {
private static final Logger logger = Logger.getLogger(RoleMgmtPermissions.class);
public static final String MAP_ROLE_SCOPE = "map-role";
protected final KeycloakSession session;
protected final RealmModel realm;
protected final AuthorizationProvider authz;
protected final MgmtPermissions root;
public RoleMgmtPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
this.session = session;
this.realm = realm;
this.authz = authz;
this.root = root;
}
public boolean isPermissionsEnabled(RoleModel role) {
return mapRolePermission(role) != null;
}
public void setPermissionsEnabled(RoleModel role, boolean enable) {
if (enable) {
ResourceServer server = getResourceServer(role);
if (authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId()) != null) {
return;
}
createResource(role);
} else {
ResourceServer server = resourceServer(role);
if (server == null) return;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
}
}
public Policy mapRolePermission(RoleModel role) {
ResourceServer server = resourceServer(role);
if (server == null) return null;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
if (resource == null) return null;
return authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
}
public Resource resource(RoleModel role) {
ResourceStore resourceStore = authz.getStoreFactory().getResourceStore();
ResourceServer server = resourceServer(role);
if (server == null) return null;
return resourceStore.findByName(getRoleResourceName(role), server.getId());
}
public ResourceServer resourceServer(RoleModel role) {
ClientModel client = getRoleClient(role);
return authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
}
/**
* Is admin allowed to map this role? In Authz terms, does the user have the "map-role" scope for the role's Authz resource?
*
* This method is hardcoded to return TRUE if any of these conditions are met:
* - The admin is from the master realm managing a different realm
* - If the Authz objects are not set up correctly for this role (resource server, resource, permission)
* - If the role's mapRole permission does not have a policy associated with it.
*
* Otherwise, it will use the Authz policy engine to resolve this answer.
*
* @param role
* @return
*/
public boolean canMapRole(RoleModel role) {
if (!root.isAdminSameRealm()) {
return true;
}
if (!isPermissionsEnabled(role)) return true; // no authz permissions set up so just allow it.
ResourceServer resourceServer = getResourceServer(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), resourceServer.getId());
if (policy.getAssociatedPolicies().isEmpty()) {
return true; // if no policies applied, just ignore
}
RealmModel oldRealm = session.getContext().getRealm();
try {
session.getContext().setRealm(realm);
Identity identity = root.identity();
EvaluationContext context = new DefaultEvaluationContext(identity, session);
DecisionResult decisionCollector = new DecisionResult();
Resource roleResource = resource(role);
Scope mapRoleScope = getMapRoleScope(resourceServer);
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
PermissionEvaluator from = authz.evaluators().from(permissions, context);
from.evaluate(decisionCollector);
if (!decisionCollector.completed()) {
logger.error("Failed to run map role policy check", decisionCollector.getError());
return false;
}
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
} finally {
session.getContext().setRealm(oldRealm);
}
}
private ClientModel getRoleClient(RoleModel role) {
ClientModel client = null;
if (role.getContainer() instanceof ClientModel) {
client = (ClientModel)role.getContainer();
} else {
client = root.getRealmManagementClient();
}
return client;
}
public Policy manageUsersPolicy(ResourceServer server) {
RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_USERS);
return rolePolicy(server, role);
}
public Policy rolePolicy(ResourceServer server, RoleModel role) {
String policyName = Helper.getRolePolicyName(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(policyName, server.getId());
if (policy != null) return policy;
return Helper.createRolePolicy(authz, server, role, policyName);
}
private Scope getMapRoleScope(ResourceServer server) {
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_SCOPE, server.getId());
if (scope == null) {
scope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_SCOPE, server);
}
return scope;
}
private Resource createResource(RoleModel role) {
ResourceServer server = getResourceServer(role);
Resource resource = authz.getStoreFactory().getResourceStore().create(getRoleResourceName(role), server, server.getClientId());
resource.setType("Role");
Scope mapRoleScope = getMapRoleScope(server);
Helper.addEmptyScopePermission(authz, server, getMapRoleScopePermissionName(role), resource, mapRoleScope);
return resource;
}
private String getMapRoleScopePermissionName(RoleModel role) {
return MAP_ROLE_SCOPE + ".permission." + role.getName();
}
private ResourceServer getResourceServer(RoleModel role) {
ClientModel client = getRoleClient(role);
return root.findOrCreateResourceServer(client);
}
private static String getRoleResourceName(RoleModel role) {
return "role.resource." + role.getName();
}
}

View file

@ -1,246 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.admin.permissions;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.Decision;
import org.keycloak.authorization.common.DefaultEvaluationContext;
import org.keycloak.authorization.identity.Identity;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.permission.ResourcePermission;
import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
import org.keycloak.authorization.policy.evaluation.DecisionResult;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.util.Permissions;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.resources.admin.RealmAuth;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Manages default policies for all users.
*
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UsersPermissions {
private static final Logger logger = Logger.getLogger(UsersPermissions.class);
public static final String MANAGE_PERMISSION_USERS = "manage.permission.users";
public static final String USERS_RESOURCE = "Users";
protected final KeycloakSession session;
protected final RealmModel realm;
protected final AuthorizationProvider authz;
protected final MgmtPermissions root;
public UsersPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
this.session = session;
this.realm = realm;
this.authz = authz;
this.root = root;
}
private void initialize() {
ClientModel client = root.getRealmManagementClient();
ResourceServer server = root.findOrCreateResourceServer(client);
Scope manageScope = authz.getStoreFactory().getScopeStore().findByName(MgmtPermissions.MANAGE_SCOPE, server.getId());
if (manageScope == null) {
manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
}
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (usersResource == null) {
usersResource = authz.getStoreFactory().getResourceStore().create(USERS_RESOURCE, server, server.getClientId());
}
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
if (policy == null) {
Set<Scope> scopeset = new HashSet<>();
scopeset.add(manageScope);
usersResource.updateScopes(scopeset);
Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
Helper.addScopePermission(authz, server, MANAGE_PERMISSION_USERS, usersResource, manageScope, manageUsersPolicy);
}
}
public boolean isPermissionsEnabled() {
ResourceServer server = resourceServer();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return false;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
return policy != null;
}
public void setPermissionsEnabled(boolean enable) {
ClientModel client = root.getRealmManagementClient();
if (enable) {
initialize();
} else {
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) return;
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (usersResource == null) {
authz.getStoreFactory().getResourceStore().delete(usersResource.getId());
}
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
if (policy == null) {
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
}
}
}
private Resource getUsersResource(ResourceServer server) {
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (usersResource == null) {
usersResource = authz.getStoreFactory().getResourceStore().create(USERS_RESOURCE, server, server.getClientId());
}
return usersResource;
}
private Scope getManageScope(ResourceServer server) {
Scope manageScope = authz.getStoreFactory().getScopeStore().findByName(MgmtPermissions.MANAGE_SCOPE, server.getId());
if (manageScope == null) {
manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
}
return manageScope;
}
private ResourceServer getRealmManagementResourceServer() {
ClientModel client = root.getRealmManagementClient();
return root.findOrCreateResourceServer(client);
}
private boolean canManageDefault(UserModel admin) {
RealmAuth auth = root.getRealmAuth();
if (auth != null) {
auth.init(RealmAuth.Resource.USER);
return auth.hasManage();
} else {
ClientModel client = root.getRealmManagementClient();
RoleModel manageUsers = client.getRole(AdminRoles.MANAGE_USERS);
return admin.hasRole(manageUsers);
}
}
public boolean canManage() {
if (root.getRealmAuth() == null) {
throw new NullPointerException("Realm auth null");
}
return canManage(root.getRealmAuth().getAuth().getUser());
}
public Resource resource() {
ResourceServer server = resourceServer();
if (server == null) return null;
return authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
}
/**
* Is admin allowed to manage users? In Authz terms, does the admin have the "map-role" scope for the role's Authz resource?
*
* This method will follow the old default behavior (does the admin have the manage-users role) if any of these conditions
* are met.:
* - The admin is from the master realm managing a different realm
* - If the Authz objects are not set up correctly for the Users resource in Authz
* - The "manage" permission for the Users resource has an empty associatedPolicy list.
*
* Otherwise, it will use the Authz policy engine to resolve this answer.
*
* @param admin
* @return
*/
public boolean canManage(UserModel admin) {
if (!root.isAdminSameRealm()) {
return canManageDefault(admin);
}
ResourceServer server = resourceServer();
if (server == null) return canManageDefault(admin);
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return canManageDefault(admin);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
if (policy == null) {
return canManageDefault(admin);
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canManageDefault(admin);
}
RealmModel oldRealm = session.getContext().getRealm();
try {
session.getContext().setRealm(realm);
Identity identity = root.identity();
EvaluationContext context = new DefaultEvaluationContext(identity, session);
DecisionResult decisionCollector = new DecisionResult();
ResourceServer resourceServer = getRealmManagementResourceServer();
Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, resourceServer.getId());
Scope manageScope = getManageScope(resourceServer);
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, manageScope);
PermissionEvaluator from = authz.evaluators().from(permissions, context);
from.evaluate(decisionCollector);
if (!decisionCollector.completed()) {
logger.error("Failed to run Users manage check", decisionCollector.getError());
return false;
}
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
} finally {
session.getContext().setRealm(oldRealm);
}
}
public ResourceServer resourceServer() {
ResourceServerStore resourceServerStore = authz.getStoreFactory().getResourceServerStore();
ClientModel client = root.getRealmManagementClient();
return authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
}
public Policy managePermission() {
ResourceServer server = resourceServer();
return authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
}
}

View file

@ -98,4 +98,7 @@ public class AdminAuth {
return false; return false;
} }
public enum Resource {
CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION, AUTHORIZATION
}
} }

View file

@ -26,6 +26,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserLoginFailureModel; import org.keycloak.models.UserLoginFailureModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.services.managers.BruteForceProtector; import org.keycloak.services.managers.BruteForceProtector;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@ -48,7 +49,7 @@ import java.util.Map;
*/ */
public class AttackDetectionResource { public class AttackDetectionResource {
protected static final Logger logger = Logger.getLogger(AttackDetectionResource.class); protected static final Logger logger = Logger.getLogger(AttackDetectionResource.class);
protected RealmAuth auth; protected AdminPermissionEvaluator auth;
protected RealmModel realm; protected RealmModel realm;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
@ -64,12 +65,10 @@ public class AttackDetectionResource {
@Context @Context
protected HttpHeaders headers; protected HttpHeaders headers;
public AttackDetectionResource(RealmAuth auth, RealmModel realm, AdminEventBuilder adminEvent) { public AttackDetectionResource(AdminPermissionEvaluator auth, RealmModel realm, AdminEventBuilder adminEvent) {
this.auth = auth; this.auth = auth;
this.realm = realm; this.realm = realm;
this.adminEvent = adminEvent.realm(realm).resource(ResourceType.USER_LOGIN_FAILURE); this.adminEvent = adminEvent.realm(realm).resource(ResourceType.USER_LOGIN_FAILURE);
auth.init(RealmAuth.Resource.USER);
} }
/** /**
@ -83,7 +82,8 @@ public class AttackDetectionResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Map<String, Object> bruteForceUserStatus(@PathParam("userId") String userId) { public Map<String, Object> bruteForceUserStatus(@PathParam("userId") String userId) {
auth.requireView(); UserModel user = session.users().getUserById(userId, realm);
auth.users().requireView(user);
Map<String, Object> data = new HashMap<>(); Map<String, Object> data = new HashMap<>();
data.put("disabled", false); data.put("disabled", false);
@ -92,7 +92,6 @@ public class AttackDetectionResource {
data.put("lastIPFailure", "n/a"); data.put("lastIPFailure", "n/a");
if (!realm.isBruteForceProtected()) return data; if (!realm.isBruteForceProtected()) return data;
UserModel user = session.users().getUserById(userId, realm);
UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId); UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId);
if (model == null) return data; if (model == null) return data;
@ -115,10 +114,10 @@ public class AttackDetectionResource {
@Path("brute-force/users/{userId}") @Path("brute-force/users/{userId}")
@DELETE @DELETE
public void clearBruteForceForUser(@PathParam("userId") String userId) { public void clearBruteForceForUser(@PathParam("userId") String userId) {
auth.requireManage();
UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId); UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId);
if (model != null) { if (model != null) {
UserModel user = session.users().getUserById(userId, realm);
auth.users().requireView(user);
session.sessions().removeUserLoginFailure(realm, userId); session.sessions().removeUserLoginFailure(realm, userId);
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success(); adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
} }
@ -133,7 +132,7 @@ public class AttackDetectionResource {
@Path("brute-force/users") @Path("brute-force/users")
@DELETE @DELETE
public void clearAllBruteForce() { public void clearAllBruteForce() {
auth.requireManage(); auth.users().requireManage();
session.sessions().removeAllUserLoginFailures(realm); session.sessions().removeAllUserLoginFailures(realm);
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success(); adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();

View file

@ -50,6 +50,7 @@ import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderRepresentation; import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.utils.CredentialHelper; import org.keycloak.utils.CredentialHelper;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -80,18 +81,17 @@ public class AuthenticationManagementResource {
private final RealmModel realm; private final RealmModel realm;
private final KeycloakSession session; private final KeycloakSession session;
private RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
@Context @Context
private UriInfo uriInfo; private UriInfo uriInfo;
protected static final Logger logger = Logger.getLogger(AuthenticationManagementResource.class); protected static final Logger logger = Logger.getLogger(AuthenticationManagementResource.class);
public AuthenticationManagementResource(RealmModel realm, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) { public AuthenticationManagementResource(RealmModel realm, KeycloakSession session, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.session = session; this.session = session;
this.auth = auth; this.auth = auth;
this.auth.init(RealmAuth.Resource.REALM);
this.adminEvent = adminEvent.resource(ResourceType.AUTH_FLOW); this.adminEvent = adminEvent.resource(ResourceType.AUTH_FLOW);
} }
@ -105,7 +105,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<Map<String, Object>> getFormProviders() { public List<Map<String, Object>> getFormProviders() {
auth.requireView(); auth.realm().requireViewRealm();
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAuthenticator.class); List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAuthenticator.class);
return buildProviderMetadata(factories); return buildProviderMetadata(factories);
@ -121,7 +121,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<Map<String, Object>> getAuthenticatorProviders() { public List<Map<String, Object>> getAuthenticatorProviders() {
auth.requireView(); auth.realm().requireViewRealm();
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(Authenticator.class); List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(Authenticator.class);
return buildProviderMetadata(factories); return buildProviderMetadata(factories);
@ -137,7 +137,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<Map<String, Object>> getClientAuthenticatorProviders() { public List<Map<String, Object>> getClientAuthenticatorProviders() {
auth.requireAny(); auth.realm().requireViewRealm();
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class); List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);
return buildProviderMetadata(factories); return buildProviderMetadata(factories);
@ -167,7 +167,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<Map<String, Object>> getFormActionProviders() { public List<Map<String, Object>> getFormActionProviders() {
auth.requireView(); auth.realm().requireViewRealm();
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAction.class); List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAction.class);
return buildProviderMetadata(factories); return buildProviderMetadata(factories);
@ -184,7 +184,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<AuthenticationFlowRepresentation> getFlows() { public List<AuthenticationFlowRepresentation> getFlows() {
auth.requireAny(); auth.realm().requireViewRealm();
List<AuthenticationFlowRepresentation> flows = new LinkedList<>(); List<AuthenticationFlowRepresentation> flows = new LinkedList<>();
for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) { for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
@ -207,7 +207,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response createFlow(AuthenticationFlowRepresentation flow) { public Response createFlow(AuthenticationFlowRepresentation flow) {
auth.requireManage(); auth.realm().requireManageRealm();
if (flow.getAlias() == null || flow.getAlias().isEmpty()) { if (flow.getAlias() == null || flow.getAlias().isEmpty()) {
return ErrorResponse.exists("Failed to create flow with empty alias name"); return ErrorResponse.exists("Failed to create flow with empty alias name");
@ -235,7 +235,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public AuthenticationFlowRepresentation getFlow(@PathParam("id") String id) { public AuthenticationFlowRepresentation getFlow(@PathParam("id") String id) {
auth.requireView(); auth.realm().requireViewRealm();
AuthenticationFlowModel flow = realm.getAuthenticationFlowById(id); AuthenticationFlowModel flow = realm.getAuthenticationFlowById(id);
if (flow == null) { if (flow == null) {
@ -253,7 +253,7 @@ public class AuthenticationManagementResource {
@DELETE @DELETE
@NoCache @NoCache
public void deleteFlow(@PathParam("id") String id) { public void deleteFlow(@PathParam("id") String id) {
auth.requireManage(); auth.realm().requireManageRealm();
deleteFlow(id, true); deleteFlow(id, true);
} }
@ -292,7 +292,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response copy(@PathParam("flowAlias") String flowAlias, Map<String, String> data) { public Response copy(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
auth.requireManage(); auth.realm().requireManageRealm();
String newName = data.get("newName"); String newName = data.get("newName");
if (realm.getFlowByAlias(newName) != null) { if (realm.getFlowByAlias(newName) != null) {
@ -351,7 +351,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response addExecutionFlow(@PathParam("flowAlias") String flowAlias, Map<String, String> data) { public Response addExecutionFlow(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias); AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias);
if (parentFlow == null) { if (parentFlow == null) {
@ -403,7 +403,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void addExecution(@PathParam("flowAlias") String flowAlias, Map<String, String> data) { public void addExecution(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias); AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias);
if (parentFlow == null) { if (parentFlow == null) {
@ -450,7 +450,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response getExecutions(@PathParam("flowAlias") String flowAlias) { public Response getExecutions(@PathParam("flowAlias") String flowAlias) {
auth.requireView(); auth.realm().requireViewRealm();
AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias); AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias);
if (flow == null) { if (flow == null) {
@ -535,7 +535,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void updateExecutions(@PathParam("flowAlias") String flowAlias, AuthenticationExecutionInfoRepresentation rep) { public void updateExecutions(@PathParam("flowAlias") String flowAlias, AuthenticationExecutionInfoRepresentation rep) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias); AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias);
if (flow == null) { if (flow == null) {
@ -566,7 +566,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response addExecution(AuthenticationExecutionRepresentation execution) { public Response addExecution(AuthenticationExecutionRepresentation execution) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticationExecutionModel model = RepresentationToModel.toModel(realm, execution); AuthenticationExecutionModel model = RepresentationToModel.toModel(realm, execution);
AuthenticationFlowModel parentFlow = getParentFlow(model); AuthenticationFlowModel parentFlow = getParentFlow(model);
@ -601,7 +601,7 @@ public class AuthenticationManagementResource {
@POST @POST
@NoCache @NoCache
public void raisePriority(@PathParam("executionId") String execution) { public void raisePriority(@PathParam("executionId") String execution) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution); AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) { if (model == null) {
@ -647,7 +647,7 @@ public class AuthenticationManagementResource {
@POST @POST
@NoCache @NoCache
public void lowerPriority(@PathParam("executionId") String execution) { public void lowerPriority(@PathParam("executionId") String execution) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution); AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) { if (model == null) {
@ -687,7 +687,7 @@ public class AuthenticationManagementResource {
@DELETE @DELETE
@NoCache @NoCache
public void removeExecution(@PathParam("executionId") String execution) { public void removeExecution(@PathParam("executionId") String execution) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution); AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) { if (model == null) {
@ -723,7 +723,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response newExecutionConfig(@PathParam("executionId") String execution, AuthenticatorConfigRepresentation json) { public Response newExecutionConfig(@PathParam("executionId") String execution, AuthenticatorConfigRepresentation json) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution); AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) { if (model == null) {
@ -753,7 +753,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("executionId") String execution,@PathParam("id") String id) { public AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("executionId") String execution,@PathParam("id") String id) {
auth.requireView(); auth.realm().requireViewRealm();
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id); AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
if (config == null) { if (config == null) {
@ -773,7 +773,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<Map<String, String>> getUnregisteredRequiredActions() { public List<Map<String, String>> getUnregisteredRequiredActions() {
auth.requireView(); auth.realm().requireViewRealm();
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class); List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class);
List<Map<String, String>> unregisteredList = new LinkedList<>(); List<Map<String, String>> unregisteredList = new LinkedList<>();
@ -807,7 +807,7 @@ public class AuthenticationManagementResource {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public void registerRequiredAction(Map<String, String> data) { public void registerRequiredAction(Map<String, String> data) {
auth.requireManage(); auth.realm().requireManageRealm();
String providerId = data.get("providerId"); String providerId = data.get("providerId");
String name = data.get("name"); String name = data.get("name");
@ -834,7 +834,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RequiredActionProviderRepresentation> getRequiredActions() { public List<RequiredActionProviderRepresentation> getRequiredActions() {
auth.requireAny(); auth.realm().requireViewRealm();
List<RequiredActionProviderRepresentation> list = new LinkedList<>(); List<RequiredActionProviderRepresentation> list = new LinkedList<>();
for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) { for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) {
@ -863,7 +863,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public RequiredActionProviderRepresentation getRequiredAction(@PathParam("alias") String alias) { public RequiredActionProviderRepresentation getRequiredAction(@PathParam("alias") String alias) {
auth.requireView(); auth.realm().requireViewRealm();
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias); RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
if (model == null) { if (model == null) {
@ -883,7 +883,7 @@ public class AuthenticationManagementResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void updateRequiredAction(@PathParam("alias") String alias, RequiredActionProviderRepresentation rep) { public void updateRequiredAction(@PathParam("alias") String alias, RequiredActionProviderRepresentation rep) {
auth.requireManage(); auth.realm().requireManageRealm();
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias); RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
if (model == null) { if (model == null) {
@ -909,7 +909,7 @@ public class AuthenticationManagementResource {
@Path("required-actions/{alias}") @Path("required-actions/{alias}")
@DELETE @DELETE
public void removeRequiredAction(@PathParam("alias") String alias) { public void removeRequiredAction(@PathParam("alias") String alias) {
auth.requireManage(); auth.realm().requireManageRealm();
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias); RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
if (model == null) { if (model == null) {
@ -928,7 +928,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public AuthenticatorConfigInfoRepresentation getAuthenticatorConfigDescription(@PathParam("providerId") String providerId) { public AuthenticatorConfigInfoRepresentation getAuthenticatorConfigDescription(@PathParam("providerId") String providerId) {
auth.requireView(); auth.realm().requireViewRealm();
ConfigurableAuthenticatorFactory factory = CredentialHelper.getConfigurableAuthenticatorFactory(session, providerId); ConfigurableAuthenticatorFactory factory = CredentialHelper.getConfigurableAuthenticatorFactory(session, providerId);
if (factory == null) { if (factory == null) {
@ -959,7 +959,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public Map<String, List<ConfigPropertyRepresentation>> getPerClientConfigDescription() { public Map<String, List<ConfigPropertyRepresentation>> getPerClientConfigDescription() {
auth.requireAny(); auth.realm().requireViewRealm();
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class); List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);
@ -991,7 +991,7 @@ public class AuthenticationManagementResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response createAuthenticatorConfig(AuthenticatorConfigRepresentation rep) { public Response createAuthenticatorConfig(AuthenticatorConfigRepresentation rep) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticatorConfigModel config = realm.addAuthenticatorConfig(RepresentationToModel.toModel(rep)); AuthenticatorConfigModel config = realm.addAuthenticatorConfig(RepresentationToModel.toModel(rep));
adminEvent.operation(OperationType.CREATE).resource(ResourceType.AUTHENTICATOR_CONFIG).resourcePath(uriInfo, config.getId()).representation(rep).success(); adminEvent.operation(OperationType.CREATE).resource(ResourceType.AUTHENTICATOR_CONFIG).resourcePath(uriInfo, config.getId()).representation(rep).success();
@ -1007,7 +1007,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("id") String id) { public AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("id") String id) {
auth.requireView(); auth.realm().requireViewRealm();
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id); AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
if (config == null) { if (config == null) {
@ -1025,7 +1025,7 @@ public class AuthenticationManagementResource {
@DELETE @DELETE
@NoCache @NoCache
public void removeAuthenticatorConfig(@PathParam("id") String id) { public void removeAuthenticatorConfig(@PathParam("id") String id) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id); AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
if (config == null) { if (config == null) {
@ -1057,7 +1057,7 @@ public class AuthenticationManagementResource {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public void updateAuthenticatorConfig(@PathParam("id") String id, AuthenticatorConfigRepresentation rep) { public void updateAuthenticatorConfig(@PathParam("id") String id, AuthenticatorConfigRepresentation rep) {
auth.requireManage(); auth.realm().requireManageRealm();
AuthenticatorConfigModel exists = realm.getAuthenticatorConfigById(id); AuthenticatorConfigModel exists = realm.getAuthenticatorConfigById(id);
if (exists == null) { if (exists == null) {

View file

@ -37,6 +37,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.KeyStoreConfig; import org.keycloak.representations.KeyStoreConfig;
import org.keycloak.representations.idm.CertificateRepresentation; import org.keycloak.representations.idm.CertificateRepresentation;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.services.util.CertificateInfoHelper; import org.keycloak.services.util.CertificateInfoHelper;
import org.keycloak.util.JWKSUtils; import org.keycloak.util.JWKSUtils;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -73,13 +74,13 @@ public class ClientAttributeCertificateResource {
public static final String JSON_WEB_KEY_SET = "JSON Web Key Set"; public static final String JSON_WEB_KEY_SET = "JSON Web Key Set";
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; private AdminPermissionEvaluator auth;
protected ClientModel client; protected ClientModel client;
protected KeycloakSession session; protected KeycloakSession session;
protected AdminEventBuilder adminEvent; protected AdminEventBuilder adminEvent;
protected String attributePrefix; protected String attributePrefix;
public ClientAttributeCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, String attributePrefix, AdminEventBuilder adminEvent) { public ClientAttributeCertificateResource(RealmModel realm, AdminPermissionEvaluator auth, ClientModel client, KeycloakSession session, String attributePrefix, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.client = client; this.client = client;
@ -97,11 +98,7 @@ public class ClientAttributeCertificateResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public CertificateRepresentation getKeyInfo() { public CertificateRepresentation getKeyInfo() {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
CertificateRepresentation info = CertificateInfoHelper.getCertificateFromClient(client, attributePrefix); CertificateRepresentation info = CertificateInfoHelper.getCertificateFromClient(client, attributePrefix);
return info; return info;
@ -117,11 +114,7 @@ public class ClientAttributeCertificateResource {
@Path("generate") @Path("generate")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public CertificateRepresentation generate() { public CertificateRepresentation generate() {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
CertificateRepresentation info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId()); CertificateRepresentation info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId());
@ -145,11 +138,7 @@ public class ClientAttributeCertificateResource {
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public CertificateRepresentation uploadJks(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException { public CertificateRepresentation uploadJks(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
try { try {
CertificateRepresentation info = getCertFromRequest(input); CertificateRepresentation info = getCertFromRequest(input);
@ -175,11 +164,7 @@ public class ClientAttributeCertificateResource {
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public CertificateRepresentation uploadJksCertificate(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException { public CertificateRepresentation uploadJksCertificate(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
try { try {
CertificateRepresentation info = getCertFromRequest(input); CertificateRepresentation info = getCertFromRequest(input);
@ -194,7 +179,7 @@ public class ClientAttributeCertificateResource {
} }
private CertificateRepresentation getCertFromRequest(MultipartFormDataInput input) throws IOException { private CertificateRepresentation getCertFromRequest(MultipartFormDataInput input) throws IOException {
auth.requireManage(); auth.clients().requireManage(client);
CertificateRepresentation info = new CertificateRepresentation(); CertificateRepresentation info = new CertificateRepresentation();
Map<String, List<InputPart>> uploadForm = input.getFormDataMap(); Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
String keystoreFormat = uploadForm.get("keystoreFormat").get(0).getBodyAsString(); String keystoreFormat = uploadForm.get("keystoreFormat").get(0).getBodyAsString();
@ -279,11 +264,7 @@ public class ClientAttributeCertificateResource {
@Produces(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_OCTET_STREAM)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public byte[] getKeystore(final KeyStoreConfig config) { public byte[] getKeystore(final KeyStoreConfig config) {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
if (config.getFormat() != null && !config.getFormat().equals("JKS") && !config.getFormat().equals("PKCS12")) { if (config.getFormat() != null && !config.getFormat().equals("JKS") && !config.getFormat().equals("PKCS12")) {
throw new NotAcceptableException("Only support jks or pkcs12 format."); throw new NotAcceptableException("Only support jks or pkcs12 format.");
@ -322,11 +303,7 @@ public class ClientAttributeCertificateResource {
@Produces(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_OCTET_STREAM)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public byte[] generateAndGetKeystore(final KeyStoreConfig config) { public byte[] generateAndGetKeystore(final KeyStoreConfig config) {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
if (config.getFormat() != null && !config.getFormat().equals("JKS") && !config.getFormat().equals("PKCS12")) { if (config.getFormat() != null && !config.getFormat().equals("JKS") && !config.getFormat().equals("PKCS12")) {
throw new NotAcceptableException("Only support jks or pkcs12 format."); throw new NotAcceptableException("Only support jks or pkcs12 format.");

View file

@ -25,6 +25,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation; import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
import org.keycloak.representations.idm.ClientInitialAccessPresentation; import org.keycloak.representations.idm.ClientInitialAccessPresentation;
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils; import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -48,7 +49,7 @@ import java.util.List;
*/ */
public class ClientInitialAccessResource { public class ClientInitialAccessResource {
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
private final RealmModel realm; private final RealmModel realm;
private final AdminEventBuilder adminEvent; private final AdminEventBuilder adminEvent;
@ -58,12 +59,11 @@ public class ClientInitialAccessResource {
@Context @Context
protected UriInfo uriInfo; protected UriInfo uriInfo;
public ClientInitialAccessResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) { public ClientInitialAccessResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.auth = auth; this.auth = auth;
this.realm = realm; this.realm = realm;
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_INITIAL_ACCESS_MODEL); this.adminEvent = adminEvent.resource(ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
auth.init(RealmAuth.Resource.CLIENT);
} }
/** /**
@ -76,7 +76,7 @@ public class ClientInitialAccessResource {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public ClientInitialAccessPresentation create(ClientInitialAccessCreatePresentation config, @Context final HttpServletResponse response) { public ClientInitialAccessPresentation create(ClientInitialAccessCreatePresentation config, @Context final HttpServletResponse response) {
auth.requireManage(); auth.clients().requireManage();
int expiration = config.getExpiration() != null ? config.getExpiration() : 0; int expiration = config.getExpiration() != null ? config.getExpiration() : 0;
int count = config.getCount() != null ? config.getCount() : 1; int count = config.getCount() != null ? config.getCount() : 1;
@ -99,7 +99,7 @@ public class ClientInitialAccessResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<ClientInitialAccessPresentation> list() { public List<ClientInitialAccessPresentation> list() {
auth.requireView(); auth.clients().requireView();
List<ClientInitialAccessModel> models = session.sessions().listClientInitialAccess(realm); List<ClientInitialAccessModel> models = session.sessions().listClientInitialAccess(realm);
List<ClientInitialAccessPresentation> reps = new LinkedList<>(); List<ClientInitialAccessPresentation> reps = new LinkedList<>();
@ -113,7 +113,7 @@ public class ClientInitialAccessResource {
@DELETE @DELETE
@Path("{id}") @Path("{id}")
public void delete(final @PathParam("id") String id) { public void delete(final @PathParam("id") String id) {
auth.requireManage(); auth.clients().requireManage();
session.sessions().removeClientInitialAccessModel(realm, id); session.sessions().removeClientInitialAccessModel(realm, id);
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success(); adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();

View file

@ -37,6 +37,7 @@ import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.idm.ComponentTypeRepresentation; import org.keycloak.representations.idm.ComponentTypeRepresentation;
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy; import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy;
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyFactory; import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyFactory;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
/** /**
* @resource Client Registration Policy * @resource Client Registration Policy
@ -44,7 +45,7 @@ import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyF
*/ */
public class ClientRegistrationPolicyResource { public class ClientRegistrationPolicyResource {
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
private final RealmModel realm; private final RealmModel realm;
private final AdminEventBuilder adminEvent; private final AdminEventBuilder adminEvent;
@ -54,12 +55,11 @@ public class ClientRegistrationPolicyResource {
@Context @Context
protected UriInfo uriInfo; protected UriInfo uriInfo;
public ClientRegistrationPolicyResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) { public ClientRegistrationPolicyResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.auth = auth; this.auth = auth;
this.realm = realm; this.realm = realm;
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_INITIAL_ACCESS_MODEL); this.adminEvent = adminEvent.resource(ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
auth.init(RealmAuth.Resource.CLIENT);
} }

View file

@ -51,6 +51,7 @@ import org.keycloak.services.managers.ClientManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.services.validation.ClientValidator; import org.keycloak.services.validation.ClientValidator;
import org.keycloak.services.validation.PairwiseClientValidator; import org.keycloak.services.validation.PairwiseClientValidator;
import org.keycloak.services.validation.ValidationMessages; import org.keycloak.services.validation.ValidationMessages;
@ -89,7 +90,7 @@ import static java.lang.Boolean.TRUE;
public class ClientResource { public class ClientResource {
protected static final Logger logger = Logger.getLogger(ClientResource.class); protected static final Logger logger = Logger.getLogger(ClientResource.class);
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
protected ClientModel client; protected ClientModel client;
protected KeycloakSession session; protected KeycloakSession session;
@ -104,19 +105,19 @@ public class ClientResource {
return keycloak; return keycloak;
} }
public ClientResource(RealmModel realm, RealmAuth auth, ClientModel clientModel, KeycloakSession session, AdminEventBuilder adminEvent) { public ClientResource(RealmModel realm, AdminPermissionEvaluator auth, ClientModel clientModel, KeycloakSession session, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.client = clientModel; this.client = clientModel;
this.session = session; this.session = session;
this.adminEvent = adminEvent.resource(ResourceType.CLIENT); this.adminEvent = adminEvent.resource(ResourceType.CLIENT);
auth.init(RealmAuth.Resource.CLIENT);
} }
@Path("protocol-mappers") @Path("protocol-mappers")
public ProtocolMappersResource getProtocolMappers() { public ProtocolMappersResource getProtocolMappers() {
ProtocolMappersResource mappers = new ProtocolMappersResource(realm, client, auth, adminEvent); AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(client);
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(client);
ProtocolMappersResource mappers = new ProtocolMappersResource(realm, client, auth, adminEvent, manageCheck, viewCheck);
ResteasyProviderFactory.getInstance().injectProperties(mappers); ResteasyProviderFactory.getInstance().injectProperties(mappers);
return mappers; return mappers;
} }
@ -129,15 +130,11 @@ public class ClientResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response update(final ClientRepresentation rep) { public Response update(final ClientRepresentation rep) {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
ValidationMessages validationMessages = new ValidationMessages(); ValidationMessages validationMessages = new ValidationMessages();
if (!ClientValidator.validate(rep, validationMessages) || !PairwiseClientValidator.validate(session, rep, validationMessages)) { if (!ClientValidator.validate(rep, validationMessages) || !PairwiseClientValidator.validate(session, rep, validationMessages)) {
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale()); Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException( throw new ErrorResponseException(
validationMessages.getStringMessages(), validationMessages.getStringMessages(),
validationMessages.getStringMessages(messages), validationMessages.getStringMessages(messages),
@ -187,11 +184,7 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public ClientRepresentation getClient() { public ClientRepresentation getClient() {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
ClientRepresentation representation = ModelToRepresentation.toRepresentation(client); ClientRepresentation representation = ModelToRepresentation.toRepresentation(client);
@ -217,11 +210,7 @@ public class ClientResource {
@NoCache @NoCache
@Path("installation/providers/{providerId}") @Path("installation/providers/{providerId}")
public Response getInstallationProvider(@PathParam("providerId") String providerId) { public Response getInstallationProvider(@PathParam("providerId") String providerId) {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
ClientInstallationProvider provider = session.getProvider(ClientInstallationProvider.class, providerId); ClientInstallationProvider provider = session.getProvider(ClientInstallationProvider.class, providerId);
if (provider == null) throw new NotFoundException("Unknown Provider"); if (provider == null) throw new NotFoundException("Unknown Provider");
@ -235,7 +224,7 @@ public class ClientResource {
@DELETE @DELETE
@NoCache @NoCache
public void deleteClient() { public void deleteClient() {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) { if (client == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
@ -256,11 +245,7 @@ public class ClientResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public CredentialRepresentation regenerateSecret() { public CredentialRepresentation regenerateSecret() {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
logger.debug("regenerateSecret"); logger.debug("regenerateSecret");
UserCredentialModel cred = KeycloakModelUtils.generateSecret(client); UserCredentialModel cred = KeycloakModelUtils.generateSecret(client);
@ -279,11 +264,7 @@ public class ClientResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public ClientRepresentation regenerateRegistrationAccessToken() { public ClientRepresentation regenerateRegistrationAccessToken() {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
String token = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, realm, uriInfo, client, RegistrationAuth.AUTHENTICATED); String token = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, realm, uriInfo, client, RegistrationAuth.AUTHENTICATED);
@ -304,11 +285,7 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public CredentialRepresentation getClientSecret() { public CredentialRepresentation getClientSecret() {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
logger.debug("getClientSecret"); logger.debug("getClientSecret");
UserCredentialModel model = UserCredentialModel.secret(client.getSecret()); UserCredentialModel model = UserCredentialModel.secret(client.getSecret());
@ -323,12 +300,16 @@ public class ClientResource {
*/ */
@Path("scope-mappings") @Path("scope-mappings")
public ScopeMappedResource getScopeMappedResource() { public ScopeMappedResource getScopeMappedResource() {
return new ScopeMappedResource(realm, auth, client, session, adminEvent); AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(client);
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(client);
return new ScopeMappedResource(realm, auth, client, session, adminEvent, manageCheck, viewCheck);
} }
@Path("roles") @Path("roles")
public RoleContainerResource getRoleContainerResource() { public RoleContainerResource getRoleContainerResource() {
return new RoleContainerResource(session, uriInfo, realm, auth, client, adminEvent); AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(client);
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(client);
return new RoleContainerResource(session, uriInfo, realm, auth, client, adminEvent, manageCheck, viewCheck);
} }
/** /**
@ -341,11 +322,7 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public UserRepresentation getServiceAccountUser() { public UserRepresentation getServiceAccountUser() {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
UserModel user = session.users().getServiceAccount(client); UserModel user = session.users().getServiceAccount(client);
if (user == null) { if (user == null) {
@ -369,11 +346,7 @@ public class ClientResource {
@POST @POST
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public GlobalRequestResult pushRevocation() { public GlobalRequestResult pushRevocation() {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).resource(ResourceType.CLIENT).success(); adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).resource(ResourceType.CLIENT).success();
return new ResourceAdminManager(session).pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client); return new ResourceAdminManager(session).pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client);
@ -396,11 +369,7 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Map<String, Long> getApplicationSessionCount() { public Map<String, Long> getApplicationSessionCount() {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
Map<String, Long> map = new HashMap<>(); Map<String, Long> map = new HashMap<>();
map.put("count", session.sessions().getActiveUserSessions(client.getRealm(), client)); map.put("count", session.sessions().getActiveUserSessions(client.getRealm(), client));
@ -421,11 +390,7 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<UserSessionRepresentation> getUserSessions(@QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) { public List<UserSessionRepresentation> getUserSessions(@QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
firstResult = firstResult != null ? firstResult : -1; firstResult = firstResult != null ? firstResult : -1;
maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS; maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
@ -453,11 +418,7 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Map<String, Long> getOfflineSessionCount() { public Map<String, Long> getOfflineSessionCount() {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
Map<String, Long> map = new HashMap<>(); Map<String, Long> map = new HashMap<>();
map.put("count", session.sessions().getOfflineSessionsCount(client.getRealm(), client)); map.put("count", session.sessions().getOfflineSessionsCount(client.getRealm(), client));
@ -478,11 +439,7 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<UserSessionRepresentation> getOfflineUserSessions(@QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) { public List<UserSessionRepresentation> getOfflineUserSessions(@QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
auth.requireView(); auth.clients().requireView(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
firstResult = firstResult != null ? firstResult : -1; firstResult = firstResult != null ? firstResult : -1;
maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS; maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
@ -519,11 +476,7 @@ public class ClientResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void registerNode(Map<String, String> formParams) { public void registerNode(Map<String, String> formParams) {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
String node = formParams.get("node"); String node = formParams.get("node");
if (node == null) { if (node == null) {
@ -543,11 +496,7 @@ public class ClientResource {
@DELETE @DELETE
@NoCache @NoCache
public void unregisterNode(final @PathParam("node") String node) { public void unregisterNode(final @PathParam("node") String node) {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
if (logger.isDebugEnabled()) logger.debug("Unregister node: " + node); if (logger.isDebugEnabled()) logger.debug("Unregister node: " + node);
@ -571,11 +520,7 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public GlobalRequestResult testNodesAvailable() { public GlobalRequestResult testNodesAvailable() {
auth.requireManage(); auth.clients().requireManage(client);
if (client == null) {
throw new NotFoundException("Could not find client");
}
logger.debug("Test availability of cluster nodes"); logger.debug("Test availability of cluster nodes");
GlobalRequestResult result = new ResourceAdminManager(session).testNodesAvailability(uriInfo.getRequestUri(), realm, client); GlobalRequestResult result = new ResourceAdminManager(session).testNodesAvailability(uriInfo.getRequestUri(), realm, client);

View file

@ -19,7 +19,7 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.authorization.admin.permissions.MgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType; import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
@ -61,30 +61,29 @@ public class ClientRoleMappingsResource {
protected KeycloakSession session; protected KeycloakSession session;
protected RealmModel realm; protected RealmModel realm;
protected RealmAuth auth; protected AdminPermissionEvaluator auth;
protected RoleMapperModel user; protected RoleMapperModel user;
protected ClientModel client; protected ClientModel client;
protected AdminEventBuilder adminEvent; protected AdminEventBuilder adminEvent;
private UriInfo uriInfo; private UriInfo uriInfo;
private RoleMapperResource.ManageResourcePermissionCheck manageResourcePermissionCheck; protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
public ClientRoleMappingsResource(UriInfo uriInfo, KeycloakSession session, RealmModel realm, RealmAuth auth, RoleMapperModel user, ClientModel client, AdminEventBuilder adminEvent) { public ClientRoleMappingsResource(UriInfo uriInfo, KeycloakSession session, RealmModel realm, AdminPermissionEvaluator auth,
RoleMapperModel user, ClientModel client, AdminEventBuilder adminEvent,
AdminPermissionEvaluator.RequirePermissionCheck manageCheck, AdminPermissionEvaluator.RequirePermissionCheck viewCheck ) {
this.uriInfo = uriInfo; this.uriInfo = uriInfo;
this.session = session; this.session = session;
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.user = user; this.user = user;
this.client = client; this.client = client;
this.managePermission = manageCheck;
this.viewPermission = viewCheck;
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_ROLE_MAPPING); this.adminEvent = adminEvent.resource(ResourceType.CLIENT_ROLE_MAPPING);
} }
public void setManageCheck(RoleMapperResource.ManageResourcePermissionCheck mapperPermissions) {
this.manageResourcePermissionCheck = mapperPermissions;
}
/** /**
* Get client-level role mappings for the user, and the app * Get client-level role mappings for the user, and the app
* *
@ -94,11 +93,7 @@ public class ClientRoleMappingsResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getClientRoleMappings() { public List<RoleRepresentation> getClientRoleMappings() {
auth.requireView(); viewPermission.require();
if (user == null || client == null) {
throw new NotFoundException("Not found");
}
Set<RoleModel> mappings = user.getClientRoleMappings(client); Set<RoleModel> mappings = user.getClientRoleMappings(client);
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>(); List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
@ -120,11 +115,8 @@ public class ClientRoleMappingsResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getCompositeClientRoleMappings() { public List<RoleRepresentation> getCompositeClientRoleMappings() {
auth.requireView(); viewPermission.require();
if (user == null || client == null) {
throw new NotFoundException("Not found");
}
Set<RoleModel> roles = client.getRoles(); Set<RoleModel> roles = client.getRoles();
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>(); List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
@ -144,11 +136,7 @@ public class ClientRoleMappingsResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getAvailableClientRoleMappings() { public List<RoleRepresentation> getAvailableClientRoleMappings() {
auth.requireView(); viewPermission.require();
if (user == null || client == null) {
throw new NotFoundException("Not found");
}
Set<RoleModel> available = client.getRoles(); Set<RoleModel> available = client.getRoles();
available = available.stream().filter(r -> available = available.stream().filter(r ->
@ -171,17 +159,6 @@ public class ClientRoleMappingsResource {
return mappings; return mappings;
} }
private void checkManagePermission() {
if (manageResourcePermissionCheck == null) {
auth.requireManage();
} else {
if (!manageResourcePermissionCheck.canManage()) {
throw new ForbiddenException();
}
}
}
/** /**
* Add client-level roles to the user role mapping * Add client-level roles to the user role mapping
* *
@ -190,11 +167,7 @@ public class ClientRoleMappingsResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void addClientRoleMapping(List<RoleRepresentation> roles) { public void addClientRoleMapping(List<RoleRepresentation> roles) {
checkManagePermission(); managePermission.require();
if (user == null || client == null) {
throw new NotFoundException("Not found");
}
for (RoleRepresentation role : roles) { for (RoleRepresentation role : roles) {
RoleModel roleModel = client.getRole(role.getName()); RoleModel roleModel = client.getRole(role.getName());
@ -215,7 +188,7 @@ public class ClientRoleMappingsResource {
} }
private boolean canMapRole(RoleModel roleModel) { private boolean canMapRole(RoleModel roleModel) {
return new MgmtPermissions(session, realm, auth.getAuth()).roles().canMapRole(roleModel); return auth.roles().canMapRole(roleModel);
} }
/** /**
@ -226,11 +199,7 @@ public class ClientRoleMappingsResource {
@DELETE @DELETE
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void deleteClientRoleMapping(List<RoleRepresentation> roles) { public void deleteClientRoleMapping(List<RoleRepresentation> roles) {
checkManagePermission(); managePermission.require();
if (user == null || client == null) {
throw new NotFoundException("Not found");
}
if (roles == null) { if (roles == null) {
Set<RoleModel> roleModels = user.getClientRoleMappings(client); Set<RoleModel> roleModels = user.getClientRoleMappings(client);
@ -257,7 +226,7 @@ public class ClientRoleMappingsResource {
try { try {
user.deleteRoleMapping(roleModel); user.deleteRoleMapping(roleModel);
} catch (ModelException me) { } catch (ModelException me) {
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale()); Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()), throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),
Response.Status.BAD_REQUEST); Response.Status.BAD_REQUEST);
} }

View file

@ -31,6 +31,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ClientTemplateRepresentation; import org.keycloak.representations.idm.ClientTemplateRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -54,7 +55,7 @@ import javax.ws.rs.core.UriInfo;
public class ClientTemplateResource { public class ClientTemplateResource {
protected static final Logger logger = Logger.getLogger(ClientTemplateResource.class); protected static final Logger logger = Logger.getLogger(ClientTemplateResource.class);
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
protected ClientTemplateModel template; protected ClientTemplateModel template;
protected KeycloakSession session; protected KeycloakSession session;
@ -62,19 +63,20 @@ public class ClientTemplateResource {
@Context @Context
protected UriInfo uriInfo; protected UriInfo uriInfo;
public ClientTemplateResource(RealmModel realm, RealmAuth auth, ClientTemplateModel template, KeycloakSession session, AdminEventBuilder adminEvent) { public ClientTemplateResource(RealmModel realm, AdminPermissionEvaluator auth, ClientTemplateModel template, KeycloakSession session, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.template = template; this.template = template;
this.session = session; this.session = session;
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE); this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE);
auth.init(RealmAuth.Resource.CLIENT);
} }
@Path("protocol-mappers") @Path("protocol-mappers")
public ProtocolMappersResource getProtocolMappers() { public ProtocolMappersResource getProtocolMappers() {
ProtocolMappersResource mappers = new ProtocolMappersResource(realm, template, auth, adminEvent); AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(template);
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(template);
ProtocolMappersResource mappers = new ProtocolMappersResource(realm, template, auth, adminEvent, manageCheck, viewCheck);
ResteasyProviderFactory.getInstance().injectProperties(mappers); ResteasyProviderFactory.getInstance().injectProperties(mappers);
return mappers; return mappers;
} }
@ -86,7 +88,9 @@ public class ClientTemplateResource {
*/ */
@Path("scope-mappings") @Path("scope-mappings")
public ScopeMappedResource getScopeMappedResource() { public ScopeMappedResource getScopeMappedResource() {
return new ScopeMappedResource(realm, auth, template, session, adminEvent); AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(template);
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(template);
return new ScopeMappedResource(realm, auth, template, session, adminEvent, manageCheck, viewCheck);
} }
/** /**
@ -97,11 +101,7 @@ public class ClientTemplateResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response update(final ClientTemplateRepresentation rep) { public Response update(final ClientTemplateRepresentation rep) {
auth.requireManage(); auth.clients().requireManageTemplates();
if (template == null) {
throw new NotFoundException("Could not find client template");
}
try { try {
RepresentationToModel.updateClientTemplate(rep, template); RepresentationToModel.updateClientTemplate(rep, template);
@ -125,11 +125,8 @@ public class ClientTemplateResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public ClientTemplateRepresentation getClient() { public ClientTemplateRepresentation getClient() {
auth.requireView(); auth.clients().requireView(template);
if (template == null) {
throw new NotFoundException("Could not find client template");
}
return ModelToRepresentation.toRepresentation(template); return ModelToRepresentation.toRepresentation(template);
} }
@ -141,11 +138,7 @@ public class ClientTemplateResource {
@DELETE @DELETE
@NoCache @NoCache
public Response deleteClientTemplate() { public Response deleteClientTemplate() {
auth.requireManage(); auth.clients().requireManage(template);
if (template == null) {
throw new NotFoundException("Could not find client template");
}
try { try {
realm.removeClientTemplate(template.getId()); realm.removeClientTemplate(template.getId());

View file

@ -18,6 +18,7 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType; import org.keycloak.events.admin.ResourceType;
@ -29,6 +30,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ClientTemplateRepresentation; import org.keycloak.representations.idm.ClientTemplateRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@ -53,18 +55,16 @@ import java.util.List;
public class ClientTemplatesResource { public class ClientTemplatesResource {
protected static final Logger logger = Logger.getLogger(ClientTemplatesResource.class); protected static final Logger logger = Logger.getLogger(ClientTemplatesResource.class);
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
@Context @Context
protected KeycloakSession session; protected KeycloakSession session;
public ClientTemplatesResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) { public ClientTemplatesResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE); this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE);
auth.init(RealmAuth.Resource.CLIENT);
} }
/** /**
@ -76,22 +76,14 @@ public class ClientTemplatesResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<ClientTemplateRepresentation> getClientTemplates() { public List<ClientTemplateRepresentation> getClientTemplates() {
auth.requireView();
List<ClientTemplateRepresentation> rep = new ArrayList<>(); List<ClientTemplateRepresentation> rep = new ArrayList<>();
List<ClientTemplateModel> clientModels = realm.getClientTemplates(); List<ClientTemplateModel> clientModels = realm.getClientTemplates();
boolean view = auth.hasView(); boolean view = auth.clients().canViewTemplates();
for (ClientTemplateModel clientModel : clientModels) { for (ClientTemplateModel clientModel : clientModels) {
if (view) { if (view || auth.clients().canView(clientModel)) {
rep.add(ModelToRepresentation.toRepresentation(clientModel)); rep.add(ModelToRepresentation.toRepresentation(clientModel));
} else {
ClientTemplateRepresentation client = new ClientTemplateRepresentation();
client.setId(clientModel.getId());
client.setName(clientModel.getName());
client.setDescription(clientModel.getDescription());
client.setProtocol(clientModel.getProtocol());
rep.add(client);
} }
} }
return rep; return rep;
@ -109,7 +101,7 @@ public class ClientTemplatesResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response createClientTemplate(final @Context UriInfo uriInfo, final ClientTemplateRepresentation rep) { public Response createClientTemplate(final @Context UriInfo uriInfo, final ClientTemplateRepresentation rep) {
auth.requireManage(); auth.clients().requireManageTemplates();
try { try {
ClientTemplateModel clientModel = RepresentationToModel.createClientTemplate(session, realm, rep); ClientTemplateModel clientModel = RepresentationToModel.createClientTemplate(session, realm, rep);
@ -131,6 +123,9 @@ public class ClientTemplatesResource {
@Path("{id}") @Path("{id}")
public ClientTemplateResource getClient(final @PathParam("id") String id) { public ClientTemplateResource getClient(final @PathParam("id") String id) {
ClientTemplateModel clientModel = realm.getClientTemplateById(id); ClientTemplateModel clientModel = realm.getClientTemplateById(id);
if (clientModel == null) {
throw new NotFoundException("Could not find client template");
}
ClientTemplateResource clientResource = new ClientTemplateResource(realm, auth, clientModel, session, adminEvent); ClientTemplateResource clientResource = new ClientTemplateResource(realm, auth, clientModel, session, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(clientResource); ResteasyProviderFactory.getInstance().injectProperties(clientResource);
return clientResource; return clientResource;

View file

@ -26,6 +26,7 @@ import org.keycloak.common.Profile;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType; 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.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -34,14 +35,18 @@ import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.ClientManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.services.validation.ClientValidator; import org.keycloak.services.validation.ClientValidator;
import org.keycloak.services.validation.PairwiseClientValidator; import org.keycloak.services.validation.PairwiseClientValidator;
import org.keycloak.services.validation.ValidationMessages; import org.keycloak.services.validation.ValidationMessages;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
@ -65,18 +70,17 @@ import java.util.Properties;
public class ClientsResource { public class ClientsResource {
protected static final Logger logger = Logger.getLogger(ClientsResource.class); protected static final Logger logger = Logger.getLogger(ClientsResource.class);
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
@Context @Context
protected KeycloakSession session; protected KeycloakSession session;
public ClientsResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) { public ClientsResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.adminEvent = adminEvent.resource(ResourceType.CLIENT); this.adminEvent = adminEvent.resource(ResourceType.CLIENT);
auth.init(RealmAuth.Resource.CLIENT);
} }
/** /**
@ -85,21 +89,20 @@ public class ClientsResource {
* Returns a list of clients belonging to the realm * Returns a list of clients belonging to the realm
* *
* @param clientId filter by clientId * @param clientId filter by clientId
* @param viewableOnly filter clients that cannot be viewed in full by admin
*/ */
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<ClientRepresentation> getClients(@QueryParam("clientId") String clientId) { public List<ClientRepresentation> getClients(@QueryParam("clientId") String clientId, @QueryParam("viewableOnly") @DefaultValue("false") boolean viewableOnly) {
auth.requireAny();
List<ClientRepresentation> rep = new ArrayList<>(); List<ClientRepresentation> rep = new ArrayList<>();
if (clientId == null) { if (clientId == null) {
List<ClientModel> clientModels = realm.getClients(); List<ClientModel> clientModels = realm.getClients();
auth.clients().requireList();
boolean view = auth.hasView(); boolean view = auth.clients().canView();
for (ClientModel clientModel : clientModels) { for (ClientModel clientModel : clientModels) {
if (view) { if (view || auth.clients().canView(clientModel)) {
ClientRepresentation representation = ModelToRepresentation.toRepresentation(clientModel); ClientRepresentation representation = ModelToRepresentation.toRepresentation(clientModel);
if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) { if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
@ -111,7 +114,7 @@ public class ClientsResource {
} }
rep.add(representation); rep.add(representation);
} else { } else if (!viewableOnly) {
ClientRepresentation client = new ClientRepresentation(); ClientRepresentation client = new ClientRepresentation();
client.setId(clientModel.getId()); client.setId(clientModel.getId());
client.setClientId(clientModel.getClientId()); client.setClientId(clientModel.getClientId());
@ -120,9 +123,20 @@ public class ClientsResource {
} }
} }
} else { } else {
ClientModel client = realm.getClientByClientId(clientId); ClientModel clientModel = realm.getClientByClientId(clientId);
if (client != null) { if (clientModel != null) {
rep.add(ModelToRepresentation.toRepresentation(client)); if (auth.clients().canView(clientModel)) {
rep.add(ModelToRepresentation.toRepresentation(clientModel));
} else if (!viewableOnly && auth.clients().canList()){
ClientRepresentation client = new ClientRepresentation();
client.setId(clientModel.getId());
client.setClientId(clientModel.getClientId());
client.setDescription(clientModel.getDescription());
rep.add(client);
} else {
throw new ForbiddenException();
}
} }
} }
return rep; return rep;
@ -144,11 +158,11 @@ public class ClientsResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response createClient(final @Context UriInfo uriInfo, final ClientRepresentation rep) { public Response createClient(final @Context UriInfo uriInfo, final ClientRepresentation rep) {
auth.requireManage(); auth.clients().requireManage();
ValidationMessages validationMessages = new ValidationMessages(); ValidationMessages validationMessages = new ValidationMessages();
if (!ClientValidator.validate(rep, validationMessages) || !PairwiseClientValidator.validate(session, rep, validationMessages)) { if (!ClientValidator.validate(rep, validationMessages) || !PairwiseClientValidator.validate(session, rep, validationMessages)) {
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale()); Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException( throw new ErrorResponseException(
validationMessages.getStringMessages(), validationMessages.getStringMessages(),
validationMessages.getStringMessages(messages), validationMessages.getStringMessages(messages),
@ -190,6 +204,9 @@ public class ClientsResource {
@Path("{id}") @Path("{id}")
public ClientResource getClient(final @PathParam("id") String id) { public ClientResource getClient(final @PathParam("id") String id) {
ClientModel clientModel = realm.getClientById(id); ClientModel clientModel = realm.getClientById(id);
if (clientModel == null) {
throw new NotFoundException("Could not find client");
}
session.getContext().setClient(clientModel); session.getContext().setClient(clientModel);

View file

@ -38,7 +38,7 @@ import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.ComponentTypeRepresentation; import org.keycloak.representations.idm.ComponentTypeRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -63,7 +63,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.stream.Collectors;
/** /**
* @resource Component * @resource Component
@ -75,7 +74,7 @@ public class ComponentResource {
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
@ -91,12 +90,10 @@ public class ComponentResource {
@Context @Context
protected HttpHeaders headers; protected HttpHeaders headers;
public ComponentResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) { public ComponentResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.auth = auth; this.auth = auth;
this.realm = realm; this.realm = realm;
this.adminEvent = adminEvent.resource(ResourceType.COMPONENT); this.adminEvent = adminEvent.resource(ResourceType.COMPONENT);
auth.init(RealmAuth.Resource.REALM);
} }
@GET @GET
@ -105,7 +102,7 @@ public class ComponentResource {
public List<ComponentRepresentation> getComponents(@QueryParam("parent") String parent, public List<ComponentRepresentation> getComponents(@QueryParam("parent") String parent,
@QueryParam("type") String type, @QueryParam("type") String type,
@QueryParam("name") String name) { @QueryParam("name") String name) {
auth.requireView(); auth.realm().requireViewRealm();
List<ComponentModel> components = Collections.EMPTY_LIST; List<ComponentModel> components = Collections.EMPTY_LIST;
if (parent == null && type == null) { if (parent == null && type == null) {
components = realm.getComponents(); components = realm.getComponents();
@ -135,7 +132,7 @@ public class ComponentResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response create(ComponentRepresentation rep) { public Response create(ComponentRepresentation rep) {
auth.requireManage(); auth.realm().requireManageRealm();
try { try {
ComponentModel model = RepresentationToModel.toModel(session, rep); ComponentModel model = RepresentationToModel.toModel(session, rep);
if (model.getParentId() == null) model.setParentId(realm.getId()); if (model.getParentId() == null) model.setParentId(realm.getId());
@ -156,7 +153,7 @@ public class ComponentResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public ComponentRepresentation getComponent(@PathParam("id") String id) { public ComponentRepresentation getComponent(@PathParam("id") String id) {
auth.requireView(); auth.realm().requireViewRealm();
ComponentModel model = realm.getComponent(id); ComponentModel model = realm.getComponent(id);
if (model == null) { if (model == null) {
throw new NotFoundException("Could not find component"); throw new NotFoundException("Could not find component");
@ -169,7 +166,7 @@ public class ComponentResource {
@Path("{id}") @Path("{id}")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response updateComponent(@PathParam("id") String id, ComponentRepresentation rep) { public Response updateComponent(@PathParam("id") String id, ComponentRepresentation rep) {
auth.requireManage(); auth.realm().requireManageRealm();
try { try {
ComponentModel model = realm.getComponent(id); ComponentModel model = realm.getComponent(id);
if (model == null) { if (model == null) {
@ -188,7 +185,7 @@ public class ComponentResource {
@DELETE @DELETE
@Path("{id}") @Path("{id}")
public void removeComponent(@PathParam("id") String id) { public void removeComponent(@PathParam("id") String id) {
auth.requireManage(); auth.realm().requireManageRealm();
ComponentModel model = realm.getComponent(id); ComponentModel model = realm.getComponent(id);
if (model == null) { if (model == null) {
throw new NotFoundException("Could not find component"); throw new NotFoundException("Could not find component");
@ -199,7 +196,7 @@ public class ComponentResource {
} }
private Response localizedErrorResponse(ComponentValidationException cve) { private Response localizedErrorResponse(ComponentValidationException cve) {
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale(), "admin-messages", "messages"); Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale(), "admin-messages", "messages");
Object[] localizedParameters = cve.getParameters()==null ? null : Arrays.asList(cve.getParameters()).stream().map((Object parameter) -> { Object[] localizedParameters = cve.getParameters()==null ? null : Arrays.asList(cve.getParameters()).stream().map((Object parameter) -> {
@ -228,7 +225,7 @@ public class ComponentResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<ComponentTypeRepresentation> getSubcomponentConfig(@PathParam("id") String parentId, @QueryParam("type") String subtype) { public List<ComponentTypeRepresentation> getSubcomponentConfig(@PathParam("id") String parentId, @QueryParam("type") String subtype) {
auth.requireView(); auth.realm().requireViewRealm();
ComponentModel parent = realm.getComponent(parentId); ComponentModel parent = realm.getComponent(parentId);
if (parent == null) { if (parent == null) {
throw new NotFoundException("Could not find parent component"); throw new NotFoundException("Could not find parent component");

View file

@ -49,6 +49,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
/** /**
* @resource Groups * @resource Groups
@ -58,11 +59,11 @@ public class GroupResource {
private final RealmModel realm; private final RealmModel realm;
private final KeycloakSession session; private final KeycloakSession session;
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
private final AdminEventBuilder adminEvent; private final AdminEventBuilder adminEvent;
private final GroupModel group; private final GroupModel group;
public GroupResource(RealmModel realm, GroupModel group, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) { public GroupResource(RealmModel realm, GroupModel group, KeycloakSession session, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.session = session; this.session = session;
this.auth = auth; this.auth = auth;
@ -81,11 +82,7 @@ public class GroupResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public GroupRepresentation getGroup() { public GroupRepresentation getGroup() {
this.auth.requireView(); this.auth.groups().requireView(group);
if (group == null) {
throw new NotFoundException("Could not find group by id");
}
return ModelToRepresentation.toGroupHierarchy(group, true); return ModelToRepresentation.toGroupHierarchy(group, true);
} }
@ -98,11 +95,7 @@ public class GroupResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void updateGroup(GroupRepresentation rep) { public void updateGroup(GroupRepresentation rep) {
this.auth.requireManage(); this.auth.groups().requireManage(group);
if (group == null) {
throw new NotFoundException("Could not find group by id");
}
updateGroup(rep, group); updateGroup(rep, group);
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success(); adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
@ -112,11 +105,7 @@ public class GroupResource {
@DELETE @DELETE
public void deleteGroup() { public void deleteGroup() {
this.auth.requireManage(); this.auth.groups().requireManage(group);
if (group == null) {
throw new NotFoundException("Could not find group by id");
}
realm.removeGroup(group); realm.removeGroup(group);
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success(); adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
@ -135,11 +124,7 @@ public class GroupResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response addChild(GroupRepresentation rep) { public Response addChild(GroupRepresentation rep) {
this.auth.requireManage(); this.auth.groups().requireManage(group);
if (group == null) {
throw new NotFoundException("Could not find group by id");
}
for (GroupModel group : group.getSubGroups()) { for (GroupModel group : group.getSubGroups()) {
if (group.getName().equals(rep.getName())) { if (group.getName().equals(rep.getName())) {
@ -191,9 +176,9 @@ public class GroupResource {
@Path("role-mappings") @Path("role-mappings")
public RoleMapperResource getRoleMappings() { public RoleMapperResource getRoleMappings() {
auth.init(RealmAuth.Resource.USER); AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.groups().requireManage(group);
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.groups().requireView(group);
RoleMapperResource resource = new RoleMapperResource(realm, auth, group, adminEvent); RoleMapperResource resource = new RoleMapperResource(realm, auth, group, adminEvent, manageCheck, viewCheck);
ResteasyProviderFactory.getInstance().injectProperties(resource); ResteasyProviderFactory.getInstance().injectProperties(resource);
return resource; return resource;
@ -214,11 +199,8 @@ public class GroupResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<UserRepresentation> getMembers(@QueryParam("first") Integer firstResult, public List<UserRepresentation> getMembers(@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) { @QueryParam("max") Integer maxResults) {
auth.requireView(); this.auth.groups().requireViewMembers(group);
if (group == null) {
throw new NotFoundException("Could not find group by id");
}
firstResult = firstResult != null ? firstResult : 0; firstResult = firstResult != null ? firstResult : 0;
maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS; maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;

View file

@ -40,6 +40,7 @@ import javax.ws.rs.core.UriInfo;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
/** /**
* @resource Groups * @resource Groups
@ -49,15 +50,14 @@ public class GroupsResource {
private final RealmModel realm; private final RealmModel realm;
private final KeycloakSession session; private final KeycloakSession session;
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
private final AdminEventBuilder adminEvent; private final AdminEventBuilder adminEvent;
public GroupsResource(RealmModel realm, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) { public GroupsResource(RealmModel realm, KeycloakSession session, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.session = session; this.session = session;
this.auth = auth; this.auth = auth;
this.adminEvent = adminEvent.resource(ResourceType.GROUP); this.adminEvent = adminEvent.resource(ResourceType.GROUP);
auth.init(RealmAuth.Resource.USER);
} }
@ -72,7 +72,7 @@ public class GroupsResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<GroupRepresentation> getGroups() { public List<GroupRepresentation> getGroups() {
auth.requireView(); auth.groups().requireList();
return ModelToRepresentation.toGroupHierarchy(realm, false); return ModelToRepresentation.toGroupHierarchy(realm, false);
} }
@ -85,9 +85,10 @@ public class GroupsResource {
*/ */
@Path("{id}") @Path("{id}")
public GroupResource getGroupById(@PathParam("id") String id) { public GroupResource getGroupById(@PathParam("id") String id) {
auth.requireView();
GroupModel group = realm.getGroupById(id); GroupModel group = realm.getGroupById(id);
if (group == null) {
throw new NotFoundException("Could not find group by id");
}
GroupResource resource = new GroupResource(realm, group, session, this.auth, adminEvent); GroupResource resource = new GroupResource(realm, group, session, this.auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(resource); ResteasyProviderFactory.getInstance().injectProperties(resource);
return resource; return resource;
@ -102,7 +103,7 @@ public class GroupsResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response addTopLevelGroup(GroupRepresentation rep) { public Response addTopLevelGroup(GroupRepresentation rep) {
auth.requireManage(); auth.groups().requireManage();
for (GroupModel group : realm.getGroups()) { for (GroupModel group : realm.getGroups()) {
if (group.getName().equals(rep.getName())) { if (group.getName().equals(rep.getName())) {

View file

@ -44,6 +44,7 @@ import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation; import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -72,7 +73,7 @@ public class IdentityProviderResource {
protected static final Logger logger = Logger.getLogger(IdentityProviderResource.class); protected static final Logger logger = Logger.getLogger(IdentityProviderResource.class);
private final RealmAuth auth; private final AdminPermissionEvaluator auth;
private final RealmModel realm; private final RealmModel realm;
private final KeycloakSession session; private final KeycloakSession session;
private final IdentityProviderModel identityProviderModel; private final IdentityProviderModel identityProviderModel;
@ -80,7 +81,7 @@ public class IdentityProviderResource {
@Context private UriInfo uriInfo; @Context private UriInfo uriInfo;
public IdentityProviderResource(RealmAuth auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel, AdminEventBuilder adminEvent) { public IdentityProviderResource(AdminPermissionEvaluator auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.session = session; this.session = session;
this.identityProviderModel = identityProviderModel; this.identityProviderModel = identityProviderModel;
@ -97,7 +98,7 @@ public class IdentityProviderResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public IdentityProviderRepresentation getIdentityProvider() { public IdentityProviderRepresentation getIdentityProvider() {
this.auth.requireView(); this.auth.realm().requireViewIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -115,7 +116,7 @@ public class IdentityProviderResource {
@DELETE @DELETE
@NoCache @NoCache
public Response delete() { public Response delete() {
this.auth.requireManage(); this.auth.realm().requireManageIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -138,7 +139,7 @@ public class IdentityProviderResource {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public Response update(IdentityProviderRepresentation providerRep) { public Response update(IdentityProviderRepresentation providerRep) {
this.auth.requireManage(); this.auth.realm().requireManageIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -229,7 +230,7 @@ public class IdentityProviderResource {
@Path("export") @Path("export")
@NoCache @NoCache
public Response export(@Context UriInfo uriInfo, @QueryParam("format") String format) { public Response export(@Context UriInfo uriInfo, @QueryParam("format") String format) {
this.auth.requireView(); this.auth.realm().requireViewIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -250,7 +251,7 @@ public class IdentityProviderResource {
@Path("mapper-types") @Path("mapper-types")
@NoCache @NoCache
public Map<String, IdentityProviderMapperTypeRepresentation> getMapperTypes() { public Map<String, IdentityProviderMapperTypeRepresentation> getMapperTypes() {
this.auth.requireView(); this.auth.realm().requireViewIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -289,7 +290,7 @@ public class IdentityProviderResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<IdentityProviderMapperRepresentation> getMappers() { public List<IdentityProviderMapperRepresentation> getMappers() {
this.auth.requireView(); this.auth.realm().requireViewIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -312,7 +313,7 @@ public class IdentityProviderResource {
@Path("mappers") @Path("mappers")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response addMapper(IdentityProviderMapperRepresentation mapper) { public Response addMapper(IdentityProviderMapperRepresentation mapper) {
auth.requireManage(); this.auth.realm().requireManageIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -343,7 +344,7 @@ public class IdentityProviderResource {
@Path("mappers/{id}") @Path("mappers/{id}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public IdentityProviderMapperRepresentation getMapperById(@PathParam("id") String id) { public IdentityProviderMapperRepresentation getMapperById(@PathParam("id") String id) {
auth.requireView(); this.auth.realm().requireViewIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -365,7 +366,7 @@ public class IdentityProviderResource {
@Path("mappers/{id}") @Path("mappers/{id}")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void update(@PathParam("id") String id, IdentityProviderMapperRepresentation rep) { public void update(@PathParam("id") String id, IdentityProviderMapperRepresentation rep) {
auth.requireManage(); this.auth.realm().requireManageIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();
@ -388,7 +389,7 @@ public class IdentityProviderResource {
@NoCache @NoCache
@Path("mappers/{id}") @Path("mappers/{id}")
public void delete(@PathParam("id") String id) { public void delete(@PathParam("id") String id) {
auth.requireManage(); this.auth.realm().requireManageIdentityProviders();
if (identityProviderModel == null) { if (identityProviderModel == null) {
throw new javax.ws.rs.NotFoundException(); throw new javax.ws.rs.NotFoundException();

View file

@ -37,6 +37,7 @@ import org.keycloak.models.utils.StripSecretsUtils;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -65,14 +66,13 @@ public class IdentityProvidersResource {
private final RealmModel realm; private final RealmModel realm;
private final KeycloakSession session; private final KeycloakSession session;
private RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
public IdentityProvidersResource(RealmModel realm, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) { public IdentityProvidersResource(RealmModel realm, KeycloakSession session, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.realm = realm; this.realm = realm;
this.session = session; this.session = session;
this.auth = auth; this.auth = auth;
this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER);
this.adminEvent = adminEvent.resource(ResourceType.IDENTITY_PROVIDER); this.adminEvent = adminEvent.resource(ResourceType.IDENTITY_PROVIDER);
} }
@ -87,7 +87,7 @@ public class IdentityProvidersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response getIdentityProviders(@PathParam("provider_id") String providerId) { public Response getIdentityProviders(@PathParam("provider_id") String providerId) {
this.auth.requireView(); this.auth.realm().requireViewIdentityProviders();
IdentityProviderFactory providerFactory = getProviderFactorytById(providerId); IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
if (providerFactory != null) { if (providerFactory != null) {
return Response.ok(providerFactory).build(); return Response.ok(providerFactory).build();
@ -108,7 +108,7 @@ public class IdentityProvidersResource {
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Map<String, String> importFrom(@Context UriInfo uriInfo, MultipartFormDataInput input) throws IOException { public Map<String, String> importFrom(@Context UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
this.auth.requireManage(); this.auth.realm().requireManageIdentityProviders();
Map<String, List<InputPart>> formDataMap = input.getFormDataMap(); Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
if (!(formDataMap.containsKey("providerId") && formDataMap.containsKey("file"))) { if (!(formDataMap.containsKey("providerId") && formDataMap.containsKey("file"))) {
throw new BadRequestException(); throw new BadRequestException();
@ -134,7 +134,7 @@ public class IdentityProvidersResource {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Map<String, String> importFrom(@Context UriInfo uriInfo, Map<String, Object> data) throws IOException { public Map<String, String> importFrom(@Context UriInfo uriInfo, Map<String, Object> data) throws IOException {
this.auth.requireManage(); this.auth.realm().requireManageIdentityProviders();
if (!(data.containsKey("providerId") && data.containsKey("fromUrl"))) { if (!(data.containsKey("providerId") && data.containsKey("fromUrl"))) {
throw new BadRequestException(); throw new BadRequestException();
} }
@ -164,7 +164,7 @@ public class IdentityProvidersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<IdentityProviderRepresentation> getIdentityProviders() { public List<IdentityProviderRepresentation> getIdentityProviders() {
this.auth.requireView(); this.auth.realm().requireViewIdentityProviders();
List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>(); List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>();
@ -185,7 +185,7 @@ public class IdentityProvidersResource {
@Path("instances") @Path("instances")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response create(@Context UriInfo uriInfo, IdentityProviderRepresentation representation) { public Response create(@Context UriInfo uriInfo, IdentityProviderRepresentation representation) {
this.auth.requireManage(); this.auth.realm().requireManageIdentityProviders();
try { try {
IdentityProviderModel identityProvider = RepresentationToModel.toModel(realm, representation); IdentityProviderModel identityProvider = RepresentationToModel.toModel(realm, representation);
@ -203,7 +203,7 @@ public class IdentityProvidersResource {
@Path("instances/{alias}") @Path("instances/{alias}")
public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) { public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) {
this.auth.requireView(); this.auth.realm().requireViewIdentityProviders();
IdentityProviderModel identityProviderModel = null; IdentityProviderModel identityProviderModel = null;
for (IdentityProviderModel storedIdentityProvider : this.realm.getIdentityProviders()) { for (IdentityProviderModel storedIdentityProvider : this.realm.getIdentityProviders()) {

View file

@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeyManager; import org.keycloak.models.KeyManager;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.KeysMetadataRepresentation; import org.keycloak.representations.idm.KeysMetadataRepresentation;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
@ -43,9 +44,9 @@ public class KeyResource {
private RealmModel realm; private RealmModel realm;
private KeycloakSession session; private KeycloakSession session;
private RealmAuth auth; private AdminPermissionEvaluator auth;
public KeyResource(RealmModel realm, KeycloakSession session, RealmAuth auth) { public KeyResource(RealmModel realm, KeycloakSession session, AdminPermissionEvaluator auth) {
this.realm = realm; this.realm = realm;
this.session = session; this.session = session;
this.auth = auth; this.auth = auth;
@ -55,7 +56,7 @@ public class KeyResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public KeysMetadataRepresentation getKeyMetadata() { public KeysMetadataRepresentation getKeyMetadata() {
auth.requireView(); auth.realm().requireViewRealm();
KeyManager keystore = session.keys(); KeyManager keystore = session.keys();

View file

@ -33,7 +33,7 @@ import org.keycloak.protocol.ProtocolMapperConfigException;
import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.admin.RealmAuth.Resource; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -66,7 +66,9 @@ public class ProtocolMappersResource {
protected ProtocolMapperContainerModel client; protected ProtocolMapperContainerModel client;
protected RealmAuth auth; protected AdminPermissionEvaluator auth;
protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
protected AdminEventBuilder adminEvent; protected AdminEventBuilder adminEvent;
@ -76,13 +78,17 @@ public class ProtocolMappersResource {
@Context @Context
protected KeycloakSession session; protected KeycloakSession session;
public ProtocolMappersResource(RealmModel realm, ProtocolMapperContainerModel client, RealmAuth auth, AdminEventBuilder adminEvent) { public ProtocolMappersResource(RealmModel realm, ProtocolMapperContainerModel client, AdminPermissionEvaluator auth,
AdminEventBuilder adminEvent,
AdminPermissionEvaluator.RequirePermissionCheck managePermission,
AdminPermissionEvaluator.RequirePermissionCheck viewPermission) {
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.client = client; this.client = client;
this.adminEvent = adminEvent.resource(ResourceType.PROTOCOL_MAPPER); this.adminEvent = adminEvent.resource(ResourceType.PROTOCOL_MAPPER);
this.managePermission = managePermission;
this.viewPermission = viewPermission;
auth.init(Resource.CLIENT);
} }
/** /**
@ -96,11 +102,7 @@ public class ProtocolMappersResource {
@Path("protocol/{protocol}") @Path("protocol/{protocol}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<ProtocolMapperRepresentation> getMappersPerProtocol(@PathParam("protocol") String protocol) { public List<ProtocolMapperRepresentation> getMappersPerProtocol(@PathParam("protocol") String protocol) {
auth.requireAny(); viewPermission.require();
if (client == null) {
throw new NotFoundException("Could not find client");
}
List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>(); List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
for (ProtocolMapperModel mapper : client.getProtocolMappers()) { for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
@ -119,11 +121,7 @@ public class ProtocolMappersResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response createMapper(ProtocolMapperRepresentation rep) { public Response createMapper(ProtocolMapperRepresentation rep) {
auth.requireManage(); managePermission.require();
if (client == null) {
throw new NotFoundException("Could not find client");
}
ProtocolMapperModel model = null; ProtocolMapperModel model = null;
try { try {
@ -147,11 +145,7 @@ public class ProtocolMappersResource {
@NoCache @NoCache
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void createMapper(List<ProtocolMapperRepresentation> reps) { public void createMapper(List<ProtocolMapperRepresentation> reps) {
auth.requireManage(); managePermission.require();
if (client == null) {
throw new NotFoundException("Could not find client");
}
ProtocolMapperModel model = null; ProtocolMapperModel model = null;
for (ProtocolMapperRepresentation rep : reps) { for (ProtocolMapperRepresentation rep : reps) {
@ -172,11 +166,7 @@ public class ProtocolMappersResource {
@Path("models") @Path("models")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<ProtocolMapperRepresentation> getMappers() { public List<ProtocolMapperRepresentation> getMappers() {
auth.requireAny(); viewPermission.require();
if (client == null) {
throw new NotFoundException("Could not find client");
}
List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>(); List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
for (ProtocolMapperModel mapper : client.getProtocolMappers()) { for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
@ -196,11 +186,7 @@ public class ProtocolMappersResource {
@Path("models/{id}") @Path("models/{id}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public ProtocolMapperRepresentation getMapperById(@PathParam("id") String id) { public ProtocolMapperRepresentation getMapperById(@PathParam("id") String id) {
auth.requireAny(); viewPermission.require();
if (client == null) {
throw new NotFoundException("Could not find client");
}
ProtocolMapperModel model = client.getProtocolMapperById(id); ProtocolMapperModel model = client.getProtocolMapperById(id);
if (model == null) throw new NotFoundException("Model not found"); if (model == null) throw new NotFoundException("Model not found");
@ -218,11 +204,7 @@ public class ProtocolMappersResource {
@Path("models/{id}") @Path("models/{id}")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void update(@PathParam("id") String id, ProtocolMapperRepresentation rep) { public void update(@PathParam("id") String id, ProtocolMapperRepresentation rep) {
auth.requireManage(); managePermission.require();
if (client == null) {
throw new NotFoundException("Could not find client");
}
ProtocolMapperModel model = client.getProtocolMapperById(id); ProtocolMapperModel model = client.getProtocolMapperById(id);
if (model == null) throw new NotFoundException("Model not found"); if (model == null) throw new NotFoundException("Model not found");
@ -243,11 +225,7 @@ public class ProtocolMappersResource {
@NoCache @NoCache
@Path("models/{id}") @Path("models/{id}")
public void delete(@PathParam("id") String id) { public void delete(@PathParam("id") String id) {
auth.requireManage(); managePermission.require();
if (client == null) {
throw new NotFoundException("Could not find client");
}
ProtocolMapperModel model = client.getProtocolMapperById(id); ProtocolMapperModel model = client.getProtocolMapperById(id);
if (model == null) throw new NotFoundException("Model not found"); if (model == null) throw new NotFoundException("Model not found");
@ -264,7 +242,7 @@ public class ProtocolMappersResource {
} }
} catch (ProtocolMapperConfigException ex) { } catch (ProtocolMapperConfigException ex) {
logger.error(ex.getMessage()); logger.error(ex.getMessage());
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale()); Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(ex.getMessage(), MessageFormat.format(messages.getProperty(ex.getMessageKey(), ex.getMessage()), ex.getParameters()), throw new ErrorResponseException(ex.getMessage(), MessageFormat.format(messages.getProperty(ex.getMessageKey(), ex.getMessage()), ex.getParameters()),
Response.Status.BAD_REQUEST); Response.Status.BAD_REQUEST);
} }

View file

@ -23,9 +23,9 @@ import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.KeyPairVerifier; import org.keycloak.KeyPairVerifier;
import org.keycloak.authorization.admin.permissions.MgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
import org.keycloak.authorization.admin.permissions.UsersPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissions;
import org.keycloak.common.ClientConnection; import org.keycloak.common.ClientConnection;
import org.keycloak.common.VerificationException; import org.keycloak.common.VerificationException;
import org.keycloak.common.util.PemUtils; import org.keycloak.common.util.PemUtils;
@ -48,7 +48,6 @@ import org.keycloak.models.LDAPConstants;
import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.CacheRealmProvider; import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.UserCache; import org.keycloak.models.cache.UserCache;
@ -63,7 +62,6 @@ import org.keycloak.representations.adapters.action.GlobalRequestResult;
import org.keycloak.representations.idm.AdminEventRepresentation; import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.EventRepresentation; import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.GroupRepresentation; import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.ManagementPermissionReference; import org.keycloak.representations.idm.ManagementPermissionReference;
@ -76,7 +74,6 @@ import org.keycloak.services.managers.LDAPConnectionTestManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.managers.UserStorageSyncManager; import org.keycloak.services.managers.UserStorageSyncManager;
import org.keycloak.services.resources.admin.RealmAuth.Resource;
import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.storage.UserStorageProviderModel;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -114,7 +111,7 @@ import java.util.regex.PatternSyntaxException;
*/ */
public class RealmAdminResource { public class RealmAdminResource {
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class); protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
protected RealmAuth auth; protected AdminPermissionEvaluator auth;
protected RealmModel realm; protected RealmModel realm;
private TokenManager tokenManager; private TokenManager tokenManager;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
@ -131,13 +128,11 @@ public class RealmAdminResource {
@Context @Context
protected HttpHeaders headers; protected HttpHeaders headers;
public RealmAdminResource(RealmAuth auth, RealmModel realm, TokenManager tokenManager, AdminEventBuilder adminEvent) { public RealmAdminResource(AdminPermissionEvaluator auth, RealmModel realm, TokenManager tokenManager, AdminEventBuilder adminEvent) {
this.auth = auth; this.auth = auth;
this.realm = realm; this.realm = realm;
this.tokenManager = tokenManager; this.tokenManager = tokenManager;
this.adminEvent = adminEvent.realm(realm).resource(ResourceType.REALM); this.adminEvent = adminEvent.realm(realm).resource(ResourceType.REALM);
auth.init(RealmAuth.Resource.REALM);
} }
/** /**
@ -150,7 +145,7 @@ public class RealmAdminResource {
@POST @POST
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public ClientRepresentation convertClientDescription(String description) { public ClientRepresentation convertClientDescription(String description) {
auth.init(Resource.CLIENT).requireManage(); auth.clients().requireManage();
if (realm == null) { if (realm == null) {
throw new NotFoundException("Realm not found."); throw new NotFoundException("Realm not found.");
@ -239,7 +234,9 @@ public class RealmAdminResource {
*/ */
@Path("roles") @Path("roles")
public RoleContainerResource getRoleContainerResource() { public RoleContainerResource getRoleContainerResource() {
return new RoleContainerResource(session, uriInfo, realm, auth, realm, adminEvent); AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.realm().requireManageRealm();
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.realm().requireViewRealm();
return new RoleContainerResource(session, uriInfo, realm, auth, realm, adminEvent, manageCheck, viewCheck);
} }
/** /**
@ -253,15 +250,15 @@ public class RealmAdminResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public RealmRepresentation getRealm() { public RealmRepresentation getRealm() {
if (auth.hasView()) { if (auth.realm().canViewRealm()) {
return ModelToRepresentation.toRepresentation(realm, false); return ModelToRepresentation.toRepresentation(realm, false);
} else { } else {
auth.requireAny(); auth.realm().requireViewRealmNameList();
RealmRepresentation rep = new RealmRepresentation(); RealmRepresentation rep = new RealmRepresentation();
rep.setRealm(realm.getName()); rep.setRealm(realm.getName());
if (auth.init(Resource.IDENTITY_PROVIDER).hasView()) { if (auth.realm().canViewIdentityProviders()) {
RealmRepresentation r = ModelToRepresentation.toRepresentation(realm, false); RealmRepresentation r = ModelToRepresentation.toRepresentation(realm, false);
rep.setIdentityProviders(r.getIdentityProviders()); rep.setIdentityProviders(r.getIdentityProviders());
rep.setIdentityProviderMappers(r.getIdentityProviderMappers()); rep.setIdentityProviderMappers(r.getIdentityProviderMappers());
@ -283,7 +280,7 @@ public class RealmAdminResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response updateRealm(final RealmRepresentation rep) { public Response updateRealm(final RealmRepresentation rep) {
auth.requireManage(); auth.realm().requireManageRealm();
logger.debug("updating realm: " + realm.getName()); logger.debug("updating realm: " + realm.getName());
@ -347,7 +344,7 @@ public class RealmAdminResource {
*/ */
@DELETE @DELETE
public void deleteRealm() { public void deleteRealm() {
auth.requireManage(); auth.realm().requireManageRealm();
if (!new RealmManager(session).removeRealm(realm)) { if (!new RealmManager(session).removeRealm(realm)) {
throw new NotFoundException("Realm doesn't exist"); throw new NotFoundException("Realm doesn't exist");
@ -372,9 +369,9 @@ public class RealmAdminResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("users-management-permissions") @Path("users-management-permissions")
public ManagementPermissionReference getUserMgmtPermissions() { public ManagementPermissionReference getUserMgmtPermissions() {
auth.requireView(); auth.realm().requireViewRealm();
MgmtPermissions permissions = new MgmtPermissions(session, realm); AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
if (permissions.users().isPermissionsEnabled()) { if (permissions.users().isPermissionsEnabled()) {
return toUsersMgmtRef(permissions); return toUsersMgmtRef(permissions);
} else { } else {
@ -389,9 +386,9 @@ public class RealmAdminResource {
@NoCache @NoCache
@Path("users-management-permissions") @Path("users-management-permissions")
public ManagementPermissionReference setUsersManagementPermissionsEnabled(ManagementPermissionReference ref) { public ManagementPermissionReference setUsersManagementPermissionsEnabled(ManagementPermissionReference ref) {
auth.requireManage(); auth.realm().requireManageRealm();
MgmtPermissions permissions = new MgmtPermissions(session, realm); AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
permissions.users().setPermissionsEnabled(ref.isEnabled()); permissions.users().setPermissionsEnabled(ref.isEnabled());
if (ref.isEnabled()) { if (ref.isEnabled()) {
return toUsersMgmtRef(permissions); return toUsersMgmtRef(permissions);
@ -401,12 +398,11 @@ public class RealmAdminResource {
} }
public static ManagementPermissionReference toUsersMgmtRef(MgmtPermissions permissions) { public static ManagementPermissionReference toUsersMgmtRef(AdminPermissionManagement permissions) {
ManagementPermissionReference ref = new ManagementPermissionReference(); ManagementPermissionReference ref = new ManagementPermissionReference();
ref.setEnabled(true); ref.setEnabled(true);
ref.setResource(permissions.users().resource().getId()); ref.setResource(permissions.users().resource().getId());
Map<String, String> scopes = new HashMap<>(); Map<String, String> scopes = permissions.users().getPermissions();
scopes.put(MgmtPermissions.MANAGE_SCOPE, permissions.users().managePermission().getId());
ref.setScopePermissions(scopes); ref.setScopePermissions(scopes);
return ref; return ref;
} }
@ -449,7 +445,7 @@ public class RealmAdminResource {
@Path("push-revocation") @Path("push-revocation")
@POST @POST
public GlobalRequestResult pushRevocation() { public GlobalRequestResult pushRevocation() {
auth.requireManage(); auth.realm().requireManageRealm();
GlobalRequestResult result = new ResourceAdminManager(session).pushRealmRevocationPolicy(uriInfo.getRequestUri(), realm); GlobalRequestResult result = new ResourceAdminManager(session).pushRealmRevocationPolicy(uriInfo.getRequestUri(), realm);
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).representation(result).success(); adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).representation(result).success();
@ -464,7 +460,7 @@ public class RealmAdminResource {
@Path("logout-all") @Path("logout-all")
@POST @POST
public GlobalRequestResult logoutAll() { public GlobalRequestResult logoutAll() {
auth.init(RealmAuth.Resource.USER).requireManage(); auth.users().requireManage();
session.sessions().removeUserSessions(realm); session.sessions().removeUserSessions(realm);
GlobalRequestResult result = new ResourceAdminManager(session).logoutAll(uriInfo.getRequestUri(), realm); GlobalRequestResult result = new ResourceAdminManager(session).logoutAll(uriInfo.getRequestUri(), realm);
@ -481,7 +477,7 @@ public class RealmAdminResource {
@Path("sessions/{session}") @Path("sessions/{session}")
@DELETE @DELETE
public void deleteSession(@PathParam("session") String sessionId) { public void deleteSession(@PathParam("session") String sessionId) {
auth.init(RealmAuth.Resource.USER).requireManage(); auth.users().requireManage();
UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId); UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
if (userSession == null) throw new NotFoundException("Sesssion not found"); if (userSession == null) throw new NotFoundException("Sesssion not found");
@ -503,7 +499,7 @@ public class RealmAdminResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<Map<String, String>> getClientSessionStats() { public List<Map<String, String>> getClientSessionStats() {
auth.requireView(); auth.realm().requireViewRealm();
List<Map<String, String>> data = new LinkedList<Map<String, String>>(); List<Map<String, String>> data = new LinkedList<Map<String, String>>();
for (ClientModel client : realm.getClients()) { for (ClientModel client : realm.getClients()) {
@ -530,7 +526,7 @@ public class RealmAdminResource {
@Path("events/config") @Path("events/config")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public RealmEventsConfigRepresentation getRealmEventsConfig() { public RealmEventsConfigRepresentation getRealmEventsConfig() {
auth.init(RealmAuth.Resource.EVENTS).requireView(); auth.realm().requireViewEvents();
RealmEventsConfigRepresentation config = ModelToRepresentation.toEventsConfigReprensetation(realm); RealmEventsConfigRepresentation config = ModelToRepresentation.toEventsConfigReprensetation(realm);
if (config.getEnabledEventTypes() == null || config.getEnabledEventTypes().isEmpty()) { if (config.getEnabledEventTypes() == null || config.getEnabledEventTypes().isEmpty()) {
@ -555,7 +551,7 @@ public class RealmAdminResource {
@Path("events/config") @Path("events/config")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) { public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) {
auth.init(RealmAuth.Resource.EVENTS).requireManage(); auth.realm().requireManageEvents();
logger.debug("updating realm events config: " + realm.getName()); logger.debug("updating realm events config: " + realm.getName());
new RealmManager(session).updateRealmEventsConfig(rep, realm); new RealmManager(session).updateRealmEventsConfig(rep, realm);
@ -584,7 +580,7 @@ public class RealmAdminResource {
@QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo, @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
@QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult, @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) { @QueryParam("max") Integer maxResults) {
auth.init(RealmAuth.Resource.EVENTS).requireView(); auth.realm().requireViewEvents();
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class); EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
@ -677,7 +673,7 @@ public class RealmAdminResource {
@QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult, @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults, @QueryParam("max") Integer maxResults,
@QueryParam("resourceTypes") List<String> resourceTypes) { @QueryParam("resourceTypes") List<String> resourceTypes) {
auth.init(RealmAuth.Resource.EVENTS).requireView(); auth.realm().requireViewEvents();
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class); EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
AdminEventQuery query = eventStore.createAdminQuery().realm(realm.getId());; AdminEventQuery query = eventStore.createAdminQuery().realm(realm.getId());;
@ -770,7 +766,7 @@ public class RealmAdminResource {
@Path("events") @Path("events")
@DELETE @DELETE
public void clearEvents() { public void clearEvents() {
auth.init(RealmAuth.Resource.EVENTS).requireManage(); auth.realm().requireManageEvents();
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class); EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
eventStore.clear(realm.getId()); eventStore.clear(realm.getId());
@ -783,7 +779,7 @@ public class RealmAdminResource {
@Path("admin-events") @Path("admin-events")
@DELETE @DELETE
public void clearAdminEvents() { public void clearAdminEvents() {
auth.init(RealmAuth.Resource.EVENTS).requireManage(); auth.realm().requireManageEvents();
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class); EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
eventStore.clearAdmin(realm.getId()); eventStore.clearAdmin(realm.getId());
@ -805,7 +801,7 @@ public class RealmAdminResource {
@QueryParam("bindDn") String bindDn, @QueryParam("bindCredential") String bindCredential, @QueryParam("bindDn") String bindDn, @QueryParam("bindCredential") String bindCredential,
@QueryParam("useTruststoreSpi") String useTruststoreSpi, @QueryParam("connectionTimeout") String connectionTimeout, @QueryParam("useTruststoreSpi") String useTruststoreSpi, @QueryParam("connectionTimeout") String connectionTimeout,
@QueryParam("componentId") String componentId) { @QueryParam("componentId") String componentId) {
auth.init(RealmAuth.Resource.REALM).requireManage(); auth.realm().requireManageRealm();
if (componentId != null && bindCredential.equals(ComponentRepresentation.SECRET_VALUE)) { if (componentId != null && bindCredential.equals(ComponentRepresentation.SECRET_VALUE)) {
bindCredential = realm.getComponent(componentId).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL); bindCredential = realm.getComponent(componentId).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL);
@ -830,7 +826,7 @@ public class RealmAdminResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("default-groups") @Path("default-groups")
public List<GroupRepresentation> getDefaultGroups() { public List<GroupRepresentation> getDefaultGroups() {
auth.requireView(); auth.realm().requireViewRealm();
List<GroupRepresentation> defaults = new LinkedList<>(); List<GroupRepresentation> defaults = new LinkedList<>();
for (GroupModel group : realm.getDefaultGroups()) { for (GroupModel group : realm.getDefaultGroups()) {
@ -842,7 +838,7 @@ public class RealmAdminResource {
@NoCache @NoCache
@Path("default-groups/{groupId}") @Path("default-groups/{groupId}")
public void addDefaultGroup(@PathParam("groupId") String groupId) { public void addDefaultGroup(@PathParam("groupId") String groupId) {
auth.requireManage(); auth.realm().requireManageRealm();
GroupModel group = realm.getGroupById(groupId); GroupModel group = realm.getGroupById(groupId);
if (group == null) { if (group == null) {
@ -857,7 +853,7 @@ public class RealmAdminResource {
@NoCache @NoCache
@Path("default-groups/{groupId}") @Path("default-groups/{groupId}")
public void removeDefaultGroup(@PathParam("groupId") String groupId) { public void removeDefaultGroup(@PathParam("groupId") String groupId) {
auth.requireManage(); auth.realm().requireManageRealm();
GroupModel group = realm.getGroupById(groupId); GroupModel group = realm.getGroupById(groupId);
if (group == null) { if (group == null) {
@ -882,13 +878,12 @@ public class RealmAdminResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public GroupRepresentation getGroupByPath(@PathParam("path") String path) { public GroupRepresentation getGroupByPath(@PathParam("path") String path) {
auth.requireView();
GroupModel found = KeycloakModelUtils.findGroupByPath(realm, path); GroupModel found = KeycloakModelUtils.findGroupByPath(realm, path);
if (found == null) { if (found == null) {
throw new NotFoundException("Group path does not exist"); throw new NotFoundException("Group path does not exist");
} }
auth.groups().requireView(found);
return ModelToRepresentation.toGroupHierarchy(found, true); return ModelToRepresentation.toGroupHierarchy(found, true);
} }
@ -902,7 +897,7 @@ public class RealmAdminResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response partialImport(PartialImportRepresentation rep) { public Response partialImport(PartialImportRepresentation rep) {
auth.requireManage(); auth.realm().requireManageRealm();
PartialImportManager partialImport = new PartialImportManager(rep, session, realm, adminEvent); PartialImportManager partialImport = new PartialImportManager(rep, session, realm, adminEvent);
return partialImport.saveResources(); return partialImport.saveResources();
@ -915,7 +910,7 @@ public class RealmAdminResource {
@Path("clear-realm-cache") @Path("clear-realm-cache")
@POST @POST
public void clearRealmCache() { public void clearRealmCache() {
auth.requireManage(); auth.realm().requireManageRealm();
CacheRealmProvider cache = session.getProvider(CacheRealmProvider.class); CacheRealmProvider cache = session.getProvider(CacheRealmProvider.class);
if (cache != null) { if (cache != null) {
@ -932,7 +927,7 @@ public class RealmAdminResource {
@Path("clear-user-cache") @Path("clear-user-cache")
@POST @POST
public void clearUserCache() { public void clearUserCache() {
auth.requireManage(); auth.realm().requireManageRealm();
UserCache cache = session.getProvider(UserCache.class); UserCache cache = session.getProvider(UserCache.class);
if (cache != null) { if (cache != null) {
@ -949,7 +944,7 @@ public class RealmAdminResource {
@Path("clear-keys-cache") @Path("clear-keys-cache")
@POST @POST
public void clearKeysCache() { public void clearKeysCache() {
auth.requireManage(); auth.realm().requireManageRealm();
PublicKeyStorageProvider cache = session.getProvider(PublicKeyStorageProvider.class); PublicKeyStorageProvider cache = session.getProvider(PublicKeyStorageProvider.class);
if (cache != null) { if (cache != null) {

View file

@ -34,6 +34,8 @@ import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ForbiddenException; import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@ -191,13 +193,7 @@ public class RealmsAdminResource {
&& !auth.getRealm().equals(realm)) { && !auth.getRealm().equals(realm)) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
RealmAuth realmAuth; AdminPermissionEvaluator realmAuth = AdminPermissions.evaluator(session, realm, auth);
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
realmAuth = new RealmAuth(auth, realm.getMasterAdminClient());
} else {
realmAuth = new RealmAuth(auth, realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())));
}
AdminEventBuilder adminEvent = new AdminEventBuilder(realm, auth, session, clientConnection); AdminEventBuilder adminEvent = new AdminEventBuilder(realm, auth, session, clientConnection);
session.getContext().setRealm(realm); session.getContext().setRealm(realm);

View file

@ -19,8 +19,10 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.authorization.admin.permissions.MgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
import org.keycloak.services.resources.admin.permissions.RolePermissionManagement;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType; import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
@ -57,7 +59,7 @@ import java.util.Set;
public class RoleByIdResource extends RoleResource { public class RoleByIdResource extends RoleResource {
protected static final Logger logger = Logger.getLogger(RoleByIdResource.class); protected static final Logger logger = Logger.getLogger(RoleByIdResource.class);
private final RealmModel realm; private final RealmModel realm;
private final RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
@Context @Context
@ -66,7 +68,7 @@ public class RoleByIdResource extends RoleResource {
@Context @Context
private UriInfo uriInfo; private UriInfo uriInfo;
public RoleByIdResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) { public RoleByIdResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
super(realm); super(realm);
this.realm = realm; this.realm = realm;
@ -85,9 +87,9 @@ public class RoleByIdResource extends RoleResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public RoleRepresentation getRole(final @PathParam("role-id") String id) { public RoleRepresentation getRole(final @PathParam("role-id") String id) {
auth.requireAny();
RoleModel roleModel = getRoleModel(id); RoleModel roleModel = getRoleModel(id);
auth.roles().requireView(roleModel);
return getRole(roleModel); return getRole(roleModel);
} }
@ -96,16 +98,6 @@ public class RoleByIdResource extends RoleResource {
if (roleModel == null) { if (roleModel == null) {
throw new NotFoundException("Could not find role with id"); throw new NotFoundException("Could not find role with id");
} }
RealmAuth.Resource r = null;
if (roleModel.getContainer() instanceof RealmModel) {
r = RealmAuth.Resource.REALM;
} else if (roleModel.getContainer() instanceof ClientModel) {
r = RealmAuth.Resource.CLIENT;
} else if (roleModel.getContainer() instanceof UserModel) {
r = RealmAuth.Resource.USER;
}
auth.init(r);
return roleModel; return roleModel;
} }
@ -118,9 +110,8 @@ public class RoleByIdResource extends RoleResource {
@DELETE @DELETE
@NoCache @NoCache
public void deleteRole(final @PathParam("role-id") String id) { public void deleteRole(final @PathParam("role-id") String id) {
auth.requireManage();
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
auth.roles().requireManage(role);
deleteRole(role); deleteRole(role);
if (role.isClientRole()) { if (role.isClientRole()) {
@ -142,9 +133,8 @@ public class RoleByIdResource extends RoleResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void updateRole(final @PathParam("role-id") String id, final RoleRepresentation rep) { public void updateRole(final @PathParam("role-id") String id, final RoleRepresentation rep) {
auth.requireManage();
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
auth.roles().requireManage(role);
updateRole(rep, role); updateRole(rep, role);
if (role.isClientRole()) { if (role.isClientRole()) {
@ -166,10 +156,9 @@ public class RoleByIdResource extends RoleResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void addComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) { public void addComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
auth.requireManage();
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
addComposites(adminEvent, uriInfo, roles, role); auth.roles().requireManage(role);
addComposites(auth, adminEvent, uriInfo, roles, role);
} }
/** /**
@ -185,11 +174,10 @@ public class RoleByIdResource extends RoleResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-id") String id) { public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-id") String id) {
auth.requireAny();
if (logger.isDebugEnabled()) logger.debug("*** getRoleComposites: '" + id + "'"); if (logger.isDebugEnabled()) logger.debug("*** getRoleComposites: '" + id + "'");
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
auth.requireView(); auth.roles().requireView(role);
return getRoleComposites(role); return getRoleComposites(role);
} }
@ -204,9 +192,9 @@ public class RoleByIdResource extends RoleResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-id") String id) { public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-id") String id) {
auth.requireAny();
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
auth.roles().requireView(role);
auth.roles().requireView(role);
return getRealmRoleComposites(role); return getRealmRoleComposites(role);
} }
@ -223,9 +211,9 @@ public class RoleByIdResource extends RoleResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Set<RoleRepresentation> getClientRoleComposites(final @PathParam("role-id") String id, public Set<RoleRepresentation> getClientRoleComposites(final @PathParam("role-id") String id,
final @PathParam("client") String client) { final @PathParam("client") String client) {
auth.requireAny();
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
auth.roles().requireView(role);
ClientModel clientModel = realm.getClientById(client); ClientModel clientModel = realm.getClientById(client);
if (clientModel == null) { if (clientModel == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
@ -243,9 +231,8 @@ public class RoleByIdResource extends RoleResource {
@DELETE @DELETE
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void deleteComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) { public void deleteComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
auth.requireManage();
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
auth.roles().requireManage(role);
deleteComposites(adminEvent, uriInfo, roles, role); deleteComposites(adminEvent, uriInfo, roles, role);
} }
@ -261,24 +248,21 @@ public class RoleByIdResource extends RoleResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public ManagementPermissionReference getManagementPermissions(final @PathParam("role-id") String id) { public ManagementPermissionReference getManagementPermissions(final @PathParam("role-id") String id) {
auth.requireView();
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
auth.roles().requireView(role);
MgmtPermissions permissions = new MgmtPermissions(session, realm); AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
if (!permissions.roles().isPermissionsEnabled(role)) { if (!permissions.roles().isPermissionsEnabled(role)) {
return new ManagementPermissionReference(); return new ManagementPermissionReference();
} }
return toMgmtRef(role, permissions); return toMgmtRef(role, permissions);
} }
public static ManagementPermissionReference toMgmtRef(RoleModel role, MgmtPermissions permissions) { public static ManagementPermissionReference toMgmtRef(RoleModel role, AdminPermissionManagement permissions) {
ManagementPermissionReference ref = new ManagementPermissionReference(); ManagementPermissionReference ref = new ManagementPermissionReference();
ref.setEnabled(true); ref.setEnabled(true);
ref.setResource(permissions.roles().resource(role).getId()); ref.setResource(permissions.roles().resource(role).getId());
Map<String, String> scopes = new HashMap<>(); ref.setScopePermissions(permissions.roles().getPermissions(role));
scopes.put(RoleMgmtPermissions.MAP_ROLE_SCOPE, permissions.roles().mapRolePermission(role).getId());
ref.setScopePermissions(scopes);
return ref; return ref;
} }
@ -295,11 +279,10 @@ public class RoleByIdResource extends RoleResource {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-id") String id, ManagementPermissionReference ref) { public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-id") String id, ManagementPermissionReference ref) {
auth.requireManage();
RoleModel role = getRoleModel(id); RoleModel role = getRoleModel(id);
auth.roles().requireManage(role);
MgmtPermissions permissions = new MgmtPermissions(session, realm); AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
permissions.roles().setPermissionsEnabled(role, ref.isEnabled()); permissions.roles().setPermissionsEnabled(role, ref.isEnabled());
if (ref.isEnabled()) { if (ref.isEnabled()) {
return toMgmtRef(role, permissions); return toMgmtRef(role, permissions);

View file

@ -19,8 +19,9 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.authorization.admin.permissions.MgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType; import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
@ -37,20 +38,20 @@ import org.keycloak.services.ErrorResponse;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
import javax.ws.rs.Path; 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.core.Context; 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.UriInfo; import javax.ws.rs.core.UriInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
@ -60,13 +61,19 @@ import java.util.Set;
*/ */
public class RoleContainerResource extends RoleResource { public class RoleContainerResource extends RoleResource {
private final RealmModel realm; private final RealmModel realm;
private final RealmAuth auth; protected AdminPermissionEvaluator auth;
protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
protected RoleContainerModel roleContainer; protected RoleContainerModel roleContainer;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
private UriInfo uriInfo; private UriInfo uriInfo;
private KeycloakSession session; private KeycloakSession session;
public RoleContainerResource(KeycloakSession session, UriInfo uriInfo, RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent) { public RoleContainerResource(KeycloakSession session, UriInfo uriInfo, RealmModel realm,
AdminPermissionEvaluator auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent,
AdminPermissionEvaluator.RequirePermissionCheck managePermission,
AdminPermissionEvaluator.RequirePermissionCheck viewPermission) {
super(realm); super(realm);
this.uriInfo = uriInfo; this.uriInfo = uriInfo;
this.realm = realm; this.realm = realm;
@ -74,6 +81,8 @@ public class RoleContainerResource extends RoleResource {
this.roleContainer = roleContainer; this.roleContainer = roleContainer;
this.adminEvent = adminEvent; this.adminEvent = adminEvent;
this.session = session; this.session = session;
this.managePermission = managePermission;
this.viewPermission = viewPermission;
} }
/** /**
@ -85,11 +94,7 @@ public class RoleContainerResource extends RoleResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<RoleRepresentation> getRoles() { public List<RoleRepresentation> getRoles() {
auth.requireAny(); auth.roles().requireList(roleContainer);
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
Set<RoleModel> roleModels = roleContainer.getRoles(); Set<RoleModel> roleModels = roleContainer.getRoles();
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>(); List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
@ -108,11 +113,7 @@ public class RoleContainerResource extends RoleResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response createRole(final RoleRepresentation rep) { public Response createRole(final RoleRepresentation rep) {
auth.requireManage(); managePermission.require();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
if (rep.getName() == null) { if (rep.getName() == null) {
throw new BadRequestException(); throw new BadRequestException();
@ -151,16 +152,12 @@ public class RoleContainerResource extends RoleResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public RoleRepresentation getRole(final @PathParam("role-name") String roleName) { public RoleRepresentation getRole(final @PathParam("role-name") String roleName) {
auth.requireView();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel roleModel = roleContainer.getRole(roleName); RoleModel roleModel = roleContainer.getRole(roleName);
if (roleModel == null) { if (roleModel == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireView(roleModel);
return getRole(roleModel); return getRole(roleModel);
} }
@ -174,16 +171,11 @@ public class RoleContainerResource extends RoleResource {
@DELETE @DELETE
@NoCache @NoCache
public void deleteRole(final @PathParam("role-name") String roleName) { public void deleteRole(final @PathParam("role-name") String roleName) {
auth.requireManage();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireManage(role);
deleteRole(role); deleteRole(role);
if (role.isClientRole()) { if (role.isClientRole()) {
@ -207,16 +199,11 @@ public class RoleContainerResource extends RoleResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) { public Response updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) {
auth.requireManage();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireManage(role);
try { try {
updateRole(rep, role); updateRole(rep, role);
@ -244,17 +231,12 @@ public class RoleContainerResource extends RoleResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) { public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
auth.requireManage();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
addComposites(adminEvent, uriInfo, roles, role); auth.roles().requireManage(role);
addComposites(auth, adminEvent, uriInfo, roles, role);
} }
/** /**
@ -268,16 +250,11 @@ public class RoleContainerResource extends RoleResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-name") String roleName) { public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-name") String roleName) {
auth.requireView();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireView(role);
return getRoleComposites(role); return getRoleComposites(role);
} }
@ -292,16 +269,11 @@ public class RoleContainerResource extends RoleResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-name") String roleName) { public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-name") String roleName) {
auth.requireView();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireView(role);
return getRealmRoleComposites(role); return getRealmRoleComposites(role);
} }
@ -319,16 +291,11 @@ public class RoleContainerResource extends RoleResource {
public Set<RoleRepresentation> getClientRoleComposites(@Context final UriInfo uriInfo, public Set<RoleRepresentation> getClientRoleComposites(@Context final UriInfo uriInfo,
final @PathParam("role-name") String roleName, final @PathParam("role-name") String roleName,
final @PathParam("client") String client) { final @PathParam("client") String client) {
auth.requireView();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireView(role);
ClientModel clientModel = realm.getClientById(client); ClientModel clientModel = realm.getClientById(client);
if (client == null) { if (client == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
@ -350,16 +317,12 @@ public class RoleContainerResource extends RoleResource {
public void deleteComposites( public void deleteComposites(
final @PathParam("role-name") String roleName, final @PathParam("role-name") String roleName,
List<RoleRepresentation> roles) { List<RoleRepresentation> roles) {
auth.requireManage();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireManage(role);
deleteComposites(adminEvent, uriInfo, roles, role); deleteComposites(adminEvent, uriInfo, roles, role);
} }
@ -375,18 +338,13 @@ public class RoleContainerResource extends RoleResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public ManagementPermissionReference getManagementPermissions(final @PathParam("role-name") String roleName) { public ManagementPermissionReference getManagementPermissions(final @PathParam("role-name") String roleName) {
auth.requireView();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireView(role);
MgmtPermissions permissions = new MgmtPermissions(session, realm); AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
if (!permissions.roles().isPermissionsEnabled(role)) { if (!permissions.roles().isPermissionsEnabled(role)) {
return new ManagementPermissionReference(); return new ManagementPermissionReference();
} }
@ -406,19 +364,14 @@ public class RoleContainerResource extends RoleResource {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-name") String roleName, ManagementPermissionReference ref) { public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-name") String roleName, ManagementPermissionReference ref) {
auth.requireManage();
if (roleContainer == null) {
throw new NotFoundException("Could not find client");
}
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
if (role == null) { if (role == null) {
throw new NotFoundException("Could not find role"); throw new NotFoundException("Could not find role");
} }
auth.roles().requireManage(role);
if (ref.isEnabled()) { if (ref.isEnabled()) {
MgmtPermissions permissions = new MgmtPermissions(session, realm); AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
permissions.roles().setPermissionsEnabled(role, ref.isEnabled()); permissions.roles().setPermissionsEnabled(role, ref.isEnabled());
return RoleByIdResource.toMgmtRef(role, permissions); return RoleByIdResource.toMgmtRef(role, permissions);
} else { } else {

View file

@ -19,7 +19,7 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.authorization.admin.permissions.MgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.common.ClientConnection; import org.keycloak.common.ClientConnection;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType; import org.keycloak.events.admin.ResourceType;
@ -52,7 +52,6 @@ import javax.ws.rs.core.UriInfo;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -69,27 +68,17 @@ import java.util.stream.Collectors;
*/ */
public class RoleMapperResource { public class RoleMapperResource {
/**
* RoleMapperResource is reused bewteen GroupResource and UserResource to manage role mappings.
* We don't know what type of resource we're managing here (user or group), so we don't know how to query the policy engine to determine
* if an action is allowed.
*
*/
public interface ManageResourcePermissionCheck {
boolean canManage();
}
protected static final Logger logger = Logger.getLogger(RoleMapperResource.class); protected static final Logger logger = Logger.getLogger(RoleMapperResource.class);
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth;
private RoleMapperModel roleMapper; private RoleMapperModel roleMapper;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
private ManageResourcePermissionCheck manageResourcePermissionCheck; protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
private AdminPermissionEvaluator auth;
@Context @Context
protected ClientConnection clientConnection; protected ClientConnection clientConnection;
@ -103,18 +92,21 @@ public class RoleMapperResource {
@Context @Context
protected HttpHeaders headers; protected HttpHeaders headers;
public RoleMapperResource(RealmModel realm, RealmAuth auth, RoleMapperModel roleMapper, AdminEventBuilder adminEvent) { public RoleMapperResource(RealmModel realm,
AdminPermissionEvaluator auth,
RoleMapperModel roleMapper,
AdminEventBuilder adminEvent,
AdminPermissionEvaluator.RequirePermissionCheck manageCheck,
AdminPermissionEvaluator.RequirePermissionCheck viewCheck) {
this.auth = auth; this.auth = auth;
this.realm = realm; this.realm = realm;
this.adminEvent = adminEvent.resource(ResourceType.REALM_ROLE_MAPPING); this.adminEvent = adminEvent.resource(ResourceType.REALM_ROLE_MAPPING);
this.roleMapper = roleMapper; this.roleMapper = roleMapper;
this.managePermission = manageCheck;
this.viewPermission = viewCheck;
} }
public void setManageCheck(ManageResourcePermissionCheck mapperPermissions) {
this.manageResourcePermissionCheck = mapperPermissions;
}
/** /**
* Get role mappings * Get role mappings
* *
@ -124,11 +116,7 @@ public class RoleMapperResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public MappingsRepresentation getRoleMappings() { public MappingsRepresentation getRoleMappings() {
auth.requireView(); viewPermission.require();
if (roleMapper == null) {
throw new NotFoundException("User not found");
}
MappingsRepresentation all = new MappingsRepresentation(); MappingsRepresentation all = new MappingsRepresentation();
Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings(); Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings();
@ -173,11 +161,7 @@ public class RoleMapperResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getRealmRoleMappings() { public List<RoleRepresentation> getRealmRoleMappings() {
auth.requireView(); viewPermission.require();
if (roleMapper == null) {
throw new NotFoundException("User not found");
}
Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings(); Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings();
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>(); List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
@ -199,11 +183,7 @@ public class RoleMapperResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getCompositeRealmRoleMappings() { public List<RoleRepresentation> getCompositeRealmRoleMappings() {
auth.requireView(); viewPermission.require();
if (roleMapper == null) {
throw new NotFoundException("User not found");
}
Set<RoleModel> roles = realm.getRoles(); Set<RoleModel> roles = realm.getRoles();
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>(); List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
@ -225,11 +205,7 @@ public class RoleMapperResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getAvailableRealmRoleMappings() { public List<RoleRepresentation> getAvailableRealmRoleMappings() {
auth.requireView(); viewPermission.require();
if (roleMapper == null) {
throw new NotFoundException("User not found");
}
Set<RoleModel> available = realm.getRoles(); Set<RoleModel> available = realm.getRoles();
Set<RoleModel> set = available.stream().filter(r -> Set<RoleModel> set = available.stream().filter(r ->
@ -247,11 +223,7 @@ public class RoleMapperResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void addRealmRoleMappings(List<RoleRepresentation> roles) { public void addRealmRoleMappings(List<RoleRepresentation> roles) {
checkManagePermission(); managePermission.require();
if (roleMapper == null) {
throw new NotFoundException("User not found");
}
logger.debugv("** addRealmRoleMappings: {0}", roles); logger.debugv("** addRealmRoleMappings: {0}", roles);
@ -267,16 +239,6 @@ public class RoleMapperResource {
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success(); adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
} }
private void checkManagePermission() {
if (manageResourcePermissionCheck == null) {
auth.requireManage();
} else {
if (!manageResourcePermissionCheck.canManage()) {
throw new ForbiddenException();
}
}
}
/** /**
* Delete realm-level role mappings * Delete realm-level role mappings
* *
@ -286,11 +248,7 @@ public class RoleMapperResource {
@DELETE @DELETE
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void deleteRealmRoleMappings(List<RoleRepresentation> roles) { public void deleteRealmRoleMappings(List<RoleRepresentation> roles) {
checkManagePermission(); managePermission.require();
if (roleMapper == null) {
throw new NotFoundException("User not found");
}
logger.debug("deleteRealmRoleMappings"); logger.debug("deleteRealmRoleMappings");
if (roles == null) { if (roles == null) {
@ -313,7 +271,7 @@ public class RoleMapperResource {
try { try {
roleMapper.deleteRoleMapping(roleModel); roleMapper.deleteRoleMapping(roleModel);
} catch (ModelException me) { } catch (ModelException me) {
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale()); Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()), throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),
Response.Status.BAD_REQUEST); Response.Status.BAD_REQUEST);
} }
@ -332,16 +290,18 @@ public class RoleMapperResource {
} }
private boolean canMapRole(RoleModel roleModel) { private boolean canMapRole(RoleModel roleModel) {
return new MgmtPermissions(session, realm, auth.getAuth()).roles().canMapRole(roleModel); return auth.roles().canMapRole(roleModel);
} }
@Path("clients/{client}") @Path("clients/{client}")
public ClientRoleMappingsResource getUserClientRoleMappingsResource(@PathParam("client") String client) { public ClientRoleMappingsResource getUserClientRoleMappingsResource(@PathParam("client") String client) {
ClientModel clientModel = realm.getClientById(client); ClientModel clientModel = realm.getClientById(client);
ClientRoleMappingsResource resource = new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper, clientModel, adminEvent); if (clientModel == null) {
resource.setManageCheck(() -> { throw new NotFoundException("Client not found");
return new MgmtPermissions(session, realm, auth.getAuth()).users().canManage(); }
}); ClientRoleMappingsResource resource = new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper,
clientModel, adminEvent,
managePermission, viewPermission);
return resource; return resource;
} }

View file

@ -25,6 +25,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.util.Collections; import java.util.Collections;
@ -60,12 +61,13 @@ public abstract class RoleResource {
if (rep.isScopeParamRequired() != null) role.setScopeParamRequired(rep.isScopeParamRequired()); if (rep.isScopeParamRequired() != null) role.setScopeParamRequired(rep.isScopeParamRequired());
} }
protected void addComposites(AdminEventBuilder adminEvent, UriInfo uriInfo, List<RoleRepresentation> roles, RoleModel role) { protected void addComposites(AdminPermissionEvaluator auth, AdminEventBuilder adminEvent, UriInfo uriInfo, List<RoleRepresentation> roles, RoleModel role) {
for (RoleRepresentation rep : roles) { for (RoleRepresentation rep : roles) {
RoleModel composite = realm.getRoleById(rep.getId()); RoleModel composite = realm.getRoleById(rep.getId());
if (composite == null) { if (composite == null) {
throw new NotFoundException("Could not find composite role"); throw new NotFoundException("Could not find composite role");
} }
auth.roles().requireManage(composite);
role.addCompositeRole(composite); role.addCompositeRole(composite);
} }

View file

@ -29,6 +29,7 @@ import org.keycloak.models.ScopeContainerModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -49,19 +50,25 @@ import java.util.Set;
*/ */
public class ScopeMappedClientResource { public class ScopeMappedClientResource {
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; protected AdminPermissionEvaluator auth;
protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
protected ScopeContainerModel scopeContainer; protected ScopeContainerModel scopeContainer;
protected KeycloakSession session; protected KeycloakSession session;
protected ClientModel scopedClient; protected ClientModel scopedClient;
protected AdminEventBuilder adminEvent; protected AdminEventBuilder adminEvent;
public ScopeMappedClientResource(RealmModel realm, RealmAuth auth, ScopeContainerModel scopeContainer, KeycloakSession session, ClientModel scopedClient, AdminEventBuilder adminEvent) { public ScopeMappedClientResource(RealmModel realm, AdminPermissionEvaluator auth, ScopeContainerModel scopeContainer, KeycloakSession session, ClientModel scopedClient, AdminEventBuilder adminEvent,
AdminPermissionEvaluator.RequirePermissionCheck managePermission,
AdminPermissionEvaluator.RequirePermissionCheck viewPermission) {
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.scopeContainer = scopeContainer; this.scopeContainer = scopeContainer;
this.session = session; this.session = session;
this.scopedClient = scopedClient; this.scopedClient = scopedClient;
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_SCOPE_MAPPING); this.adminEvent = adminEvent.resource(ResourceType.CLIENT_SCOPE_MAPPING);
this.managePermission = managePermission;
this.viewPermission = viewPermission;
} }
/** /**
@ -75,11 +82,7 @@ public class ScopeMappedClientResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getClientScopeMappings() { public List<RoleRepresentation> getClientScopeMappings() {
auth.requireView(); viewPermission.require();
if (scopeContainer == null) {
throw new NotFoundException("Could not find client");
}
Set<RoleModel> mappings = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer); //scopedClient.getClientScopeMappings(client); Set<RoleModel> mappings = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer); //scopedClient.getClientScopeMappings(client);
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>(); List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
@ -101,14 +104,10 @@ public class ScopeMappedClientResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getAvailableClientScopeMappings() { public List<RoleRepresentation> getAvailableClientScopeMappings() {
auth.requireView(); viewPermission.require();
if (scopeContainer == null) {
throw new NotFoundException("Could not find client");
}
Set<RoleModel> roles = scopedClient.getRoles(); Set<RoleModel> roles = scopedClient.getRoles();
return ScopeMappedResource.getAvailable(scopeContainer, roles); return ScopeMappedResource.getAvailable(auth, scopeContainer, roles);
} }
/** /**
@ -123,11 +122,7 @@ public class ScopeMappedClientResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getCompositeClientScopeMappings() { public List<RoleRepresentation> getCompositeClientScopeMappings() {
auth.requireView(); viewPermission.require();
if (scopeContainer == null) {
throw new NotFoundException("Could not find client");
}
Set<RoleModel> roles = scopedClient.getRoles(); Set<RoleModel> roles = scopedClient.getRoles();
return ScopeMappedResource.getComposite(scopeContainer, roles); return ScopeMappedResource.getComposite(scopeContainer, roles);
@ -141,11 +136,7 @@ public class ScopeMappedClientResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void addClientScopeMapping(List<RoleRepresentation> roles) { public void addClientScopeMapping(List<RoleRepresentation> roles) {
auth.requireManage(); managePermission.require();
if (scopeContainer == null) {
throw new NotFoundException("Could not find client");
}
for (RoleRepresentation role : roles) { for (RoleRepresentation role : roles) {
RoleModel roleModel = scopedClient.getRole(role.getName()); RoleModel roleModel = scopedClient.getRole(role.getName());
@ -166,11 +157,7 @@ public class ScopeMappedClientResource {
@DELETE @DELETE
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void deleteClientScopeMapping(List<RoleRepresentation> roles) { public void deleteClientScopeMapping(List<RoleRepresentation> roles) {
auth.requireManage(); managePermission.require();
if (scopeContainer == null) {
throw new NotFoundException("Could not find client");
}
if (roles == null) { if (roles == null) {
Set<RoleModel> roleModels = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer);//scopedClient.getClientScopeMappings(client); Set<RoleModel> roleModels = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer);//scopedClient.getClientScopeMappings(client);

View file

@ -31,6 +31,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.ClientMappingsRepresentation; import org.keycloak.representations.idm.ClientMappingsRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation; import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -56,17 +57,25 @@ import java.util.Set;
*/ */
public class ScopeMappedResource { public class ScopeMappedResource {
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; protected AdminPermissionEvaluator auth;
protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
protected ScopeContainerModel scopeContainer; protected ScopeContainerModel scopeContainer;
protected KeycloakSession session; protected KeycloakSession session;
protected AdminEventBuilder adminEvent; protected AdminEventBuilder adminEvent;
public ScopeMappedResource(RealmModel realm, RealmAuth auth, ScopeContainerModel scopeContainer, KeycloakSession session, AdminEventBuilder adminEvent) { public ScopeMappedResource(RealmModel realm, AdminPermissionEvaluator auth, ScopeContainerModel scopeContainer,
KeycloakSession session, AdminEventBuilder adminEvent,
AdminPermissionEvaluator.RequirePermissionCheck managePermission,
AdminPermissionEvaluator.RequirePermissionCheck viewPermission) {
this.realm = realm; this.realm = realm;
this.auth = auth; this.auth = auth;
this.scopeContainer = scopeContainer; this.scopeContainer = scopeContainer;
this.session = session; this.session = session;
this.adminEvent = adminEvent.resource(ResourceType.REALM_SCOPE_MAPPING); this.adminEvent = adminEvent.resource(ResourceType.REALM_SCOPE_MAPPING);
this.managePermission = managePermission;
this.viewPermission = viewPermission;
} }
/** /**
@ -78,7 +87,7 @@ public class ScopeMappedResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public MappingsRepresentation getScopeMappings() { public MappingsRepresentation getScopeMappings() {
auth.requireView(); viewPermission.require();
if (scopeContainer == null) { if (scopeContainer == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
@ -126,7 +135,7 @@ public class ScopeMappedResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getRealmScopeMappings() { public List<RoleRepresentation> getRealmScopeMappings() {
auth.requireView(); viewPermission.require();
if (scopeContainer == null) { if (scopeContainer == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
@ -150,20 +159,21 @@ public class ScopeMappedResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getAvailableRealmScopeMappings() { public List<RoleRepresentation> getAvailableRealmScopeMappings() {
auth.requireView(); viewPermission.require();
if (scopeContainer == null) { if (scopeContainer == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
} }
Set<RoleModel> roles = realm.getRoles(); Set<RoleModel> roles = realm.getRoles();
return getAvailable(scopeContainer, roles); return getAvailable(auth, scopeContainer, roles);
} }
public static List<RoleRepresentation> getAvailable(ScopeContainerModel client, Set<RoleModel> roles) { public static List<RoleRepresentation> getAvailable(AdminPermissionEvaluator auth, ScopeContainerModel client, Set<RoleModel> roles) {
List<RoleRepresentation> available = new ArrayList<RoleRepresentation>(); List<RoleRepresentation> available = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) { for (RoleModel roleModel : roles) {
if (client.hasScope(roleModel)) continue; if (client.hasScope(roleModel)) continue;
if (!auth.roles().canMapClientScope(roleModel)) continue;
available.add(ModelToRepresentation.toRepresentation(roleModel)); available.add(ModelToRepresentation.toRepresentation(roleModel));
} }
return available; return available;
@ -183,7 +193,7 @@ public class ScopeMappedResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getCompositeRealmScopeMappings() { public List<RoleRepresentation> getCompositeRealmScopeMappings() {
auth.requireView(); viewPermission.require();
if (scopeContainer == null) { if (scopeContainer == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
@ -210,7 +220,7 @@ public class ScopeMappedResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void addRealmScopeMappings(List<RoleRepresentation> roles) { public void addRealmScopeMappings(List<RoleRepresentation> roles) {
auth.requireManage(); managePermission.require();
if (scopeContainer == null) { if (scopeContainer == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
@ -236,7 +246,7 @@ public class ScopeMappedResource {
@DELETE @DELETE
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void deleteRealmScopeMappings(List<RoleRepresentation> roles) { public void deleteRealmScopeMappings(List<RoleRepresentation> roles) {
auth.requireManage(); managePermission.require();
if (scopeContainer == null) { if (scopeContainer == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
@ -268,6 +278,9 @@ public class ScopeMappedResource {
@Path("clients/{client}") @Path("clients/{client}")
public ScopeMappedClientResource getClientByIdScopeMappings(@PathParam("client") String client) { public ScopeMappedClientResource getClientByIdScopeMappings(@PathParam("client") String client) {
ClientModel clientModel = realm.getClientById(client); ClientModel clientModel = realm.getClientById(client);
return new ScopeMappedClientResource(realm, auth, this.scopeContainer, session, clientModel, adminEvent); if (clientModel == null) {
throw new NotFoundException("Could not find client");
}
return new ScopeMappedClientResource(realm, auth, this.scopeContainer, session, clientModel, adminEvent, managePermission, viewPermission);
} }
} }

View file

@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.services.ServicesLogger; import org.keycloak.services.ServicesLogger;
import org.keycloak.services.managers.UserStorageSyncManager; import org.keycloak.services.managers.UserStorageSyncManager;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.ldap.LDAPStorageProvider; import org.keycloak.storage.ldap.LDAPStorageProvider;
@ -55,7 +56,7 @@ public class UserStorageProviderResource {
protected RealmModel realm; protected RealmModel realm;
protected RealmAuth auth; protected AdminPermissionEvaluator auth;
protected AdminEventBuilder adminEvent; protected AdminEventBuilder adminEvent;
@ -71,12 +72,10 @@ public class UserStorageProviderResource {
@Context @Context
protected HttpHeaders headers; protected HttpHeaders headers;
public UserStorageProviderResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) { public UserStorageProviderResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.auth = auth; this.auth = auth;
this.realm = realm; this.realm = realm;
this.adminEvent = adminEvent; this.adminEvent = adminEvent;
auth.init(RealmAuth.Resource.USER);
} }
/** /**
@ -94,7 +93,7 @@ public class UserStorageProviderResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public SynchronizationResult syncUsers(@PathParam("id") String id, public SynchronizationResult syncUsers(@PathParam("id") String id,
@QueryParam("action") String action) { @QueryParam("action") String action) {
auth.requireManage(); auth.users().requireManage();
ComponentModel model = realm.getComponent(id); ComponentModel model = realm.getComponent(id);
if (model == null) { if (model == null) {
@ -139,7 +138,7 @@ public class UserStorageProviderResource {
@Path("{id}/remove-imported-users") @Path("{id}/remove-imported-users")
@NoCache @NoCache
public void removeImportedUsers(@PathParam("id") String id) { public void removeImportedUsers(@PathParam("id") String id) {
auth.requireManage(); auth.users().requireManage();
ComponentModel model = realm.getComponent(id); ComponentModel model = realm.getComponent(id);
if (model == null) { if (model == null) {
@ -162,7 +161,7 @@ public class UserStorageProviderResource {
@Path("{id}/unlink-users") @Path("{id}/unlink-users")
@NoCache @NoCache
public void unlinkUsers(@PathParam("id") String id) { public void unlinkUsers(@PathParam("id") String id) {
auth.requireManage(); auth.users().requireManage();
ComponentModel model = realm.getComponent(id); ComponentModel model = realm.getComponent(id);
if (model == null) { if (model == null) {
@ -187,7 +186,7 @@ public class UserStorageProviderResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public SynchronizationResult syncMapperData(@PathParam("parentId") String parentId, @PathParam("id") String mapperId, @QueryParam("direction") String direction) { public SynchronizationResult syncMapperData(@PathParam("parentId") String parentId, @PathParam("id") String mapperId, @QueryParam("direction") String direction) {
auth.requireManage(); auth.users().requireManage();
ComponentModel parentModel = realm.getComponent(parentId); ComponentModel parentModel = realm.getComponent(parentId);
if (parentModel == null) throw new NotFoundException("Parent model not found"); if (parentModel == null) throw new NotFoundException("Parent model not found");

View file

@ -22,8 +22,8 @@ import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.authentication.RequiredActionProvider; import org.keycloak.authentication.RequiredActionProvider;
import org.keycloak.authorization.admin.permissions.MgmtPermissions;
import org.keycloak.authentication.actiontoken.execactions.ExecuteActionsActionToken; import org.keycloak.authentication.actiontoken.execactions.ExecuteActionsActionToken;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.common.ClientConnection; import org.keycloak.common.ClientConnection;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
@ -36,7 +36,6 @@ import org.keycloak.events.EventType;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType; import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
@ -116,7 +115,7 @@ public class UsersResource {
protected RealmModel realm; protected RealmModel realm;
private RealmAuth auth; private AdminPermissionEvaluator auth;
private AdminEventBuilder adminEvent; private AdminEventBuilder adminEvent;
@ -132,12 +131,10 @@ public class UsersResource {
@Context @Context
protected HttpHeaders headers; protected HttpHeaders headers;
public UsersResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) { public UsersResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
this.auth = auth; this.auth = auth;
this.realm = realm; this.realm = realm;
this.adminEvent = adminEvent.resource(ResourceType.USER); this.adminEvent = adminEvent.resource(ResourceType.USER);
auth.init(RealmAuth.Resource.USER);
} }
/** /**
@ -151,13 +148,13 @@ public class UsersResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response updateUser(final @PathParam("id") String id, final UserRepresentation rep) { public Response updateUser(final @PathParam("id") String id, final UserRepresentation rep) {
auth.requireManage();
try { try {
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
} }
auth.users().requireManage(user);
Set<String> attrsToRemove; Set<String> attrsToRemove;
if (rep.getAttributes() != null) { if (rep.getAttributes() != null) {
@ -188,6 +185,8 @@ public class UsersResource {
} catch (ModelException me) { } catch (ModelException me) {
logger.warn("Could not update user!", me); logger.warn("Could not update user!", me);
return ErrorResponse.exists("Could not update user!"); return ErrorResponse.exists("Could not update user!");
} catch (ForbiddenException fe) {
throw fe;
} catch (Exception me) { // JPA } catch (Exception me) { // JPA
logger.warn("Could not update user!", me);// may be committed by JTA which can't logger.warn("Could not update user!", me);// may be committed by JTA which can't
return ErrorResponse.exists("Could not update user!"); return ErrorResponse.exists("Could not update user!");
@ -206,7 +205,7 @@ public class UsersResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response createUser(final @Context UriInfo uriInfo, final UserRepresentation rep) { public Response createUser(final @Context UriInfo uriInfo, final UserRepresentation rep) {
auth.requireManage(); auth.users().requireManage();
// Double-check duplicated username and email here due to federation // Double-check duplicated username and email here due to federation
if (session.users().getUserByUsername(rep.getUsername(), realm) != null) { if (session.users().getUserByUsername(rep.getUsername(), realm) != null) {
@ -291,13 +290,13 @@ public class UsersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public UserRepresentation getUser(final @PathParam("id") String id) { public UserRepresentation getUser(final @PathParam("id") String id) {
auth.requireView();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireView(user);
UserRepresentation rep = ModelToRepresentation.toRepresentation(session, realm, user); UserRepresentation rep = ModelToRepresentation.toRepresentation(session, realm, user);
if (realm.isIdentityFederationEnabled()) { if (realm.isIdentityFederationEnabled()) {
@ -325,19 +324,17 @@ public class UsersResource {
public Map<String, Object> impersonate(final @PathParam("id") String id) { public Map<String, Object> impersonate(final @PathParam("id") String id) {
ProfileHelper.requireFeature(Profile.Feature.IMPERSONATION); ProfileHelper.requireFeature(Profile.Feature.IMPERSONATION);
auth.init(RealmAuth.Resource.IMPERSONATION);
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
RealmModel authenticatedRealm = auth.getAuth().getRealm(); auth.users().requireImpersonate(user);
RealmModel authenticatedRealm = auth.adminAuth().getRealm();
// if same realm logout before impersonation // if same realm logout before impersonation
boolean sameRealm = false; boolean sameRealm = false;
if (authenticatedRealm.getId().equals(realm.getId())) { if (authenticatedRealm.getId().equals(realm.getId())) {
sameRealm = true; sameRealm = true;
UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, auth.getAuth().getToken().getSessionState()); UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, auth.adminAuth().getToken().getSessionState());
AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection); AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection);
AuthenticationManager.expireRememberMeCookie(realm, uriInfo, clientConnection); AuthenticationManager.expireRememberMeCookie(realm, uriInfo, clientConnection);
AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, uriInfo, clientConnection, headers, true); AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, uriInfo, clientConnection, headers, true);
@ -355,7 +352,7 @@ public class UsersResource {
.session(userSession) .session(userSession)
.user(user) .user(user)
.detail(Details.IMPERSONATOR_REALM,authenticatedRealm.getName()) .detail(Details.IMPERSONATOR_REALM,authenticatedRealm.getName())
.detail(Details.IMPERSONATOR, auth.getAuth().getUser().getUsername()).success(); .detail(Details.IMPERSONATOR, auth.adminAuth().getUser().getUsername()).success();
return result; return result;
} }
@ -372,12 +369,11 @@ public class UsersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<UserSessionRepresentation> getSessions(final @PathParam("id") String id) { public List<UserSessionRepresentation> getSessions(final @PathParam("id") String id) {
auth.requireView();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireView(user);
List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user); List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user);
List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>(); List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
for (UserSessionModel session : sessions) { for (UserSessionModel session : sessions) {
@ -398,12 +394,11 @@ public class UsersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<UserSessionRepresentation> getOfflineSessions(final @PathParam("id") String id, final @PathParam("clientId") String clientId) { public List<UserSessionRepresentation> getOfflineSessions(final @PathParam("id") String id, final @PathParam("clientId") String clientId) {
auth.requireView();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireView(user);
ClientModel client = realm.getClientById(clientId); ClientModel client = realm.getClientById(clientId);
if (client == null) { if (client == null) {
throw new NotFoundException("Client not found"); throw new NotFoundException("Client not found");
@ -439,12 +434,11 @@ public class UsersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<FederatedIdentityRepresentation> getFederatedIdentity(final @PathParam("id") String id) { public List<FederatedIdentityRepresentation> getFederatedIdentity(final @PathParam("id") String id) {
auth.requireView();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireView(user);
return getFederatedIdentities(user); return getFederatedIdentities(user);
} }
@ -476,12 +470,12 @@ public class UsersResource {
@POST @POST
@NoCache @NoCache
public Response addFederatedIdentity(final @PathParam("id") String id, final @PathParam("provider") String provider, FederatedIdentityRepresentation rep) { public Response addFederatedIdentity(final @PathParam("id") String id, final @PathParam("provider") String provider, FederatedIdentityRepresentation rep) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
if (session.users().getFederatedIdentity(user, provider, realm) != null) { if (session.users().getFederatedIdentity(user, provider, realm) != null) {
return ErrorResponse.exists("User is already linked with provider"); return ErrorResponse.exists("User is already linked with provider");
} }
@ -502,12 +496,11 @@ public class UsersResource {
@DELETE @DELETE
@NoCache @NoCache
public void removeFederatedIdentity(final @PathParam("id") String id, final @PathParam("provider") String provider) { public void removeFederatedIdentity(final @PathParam("id") String id, final @PathParam("provider") String provider) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
if (!session.users().removeFederatedIdentity(realm, user, provider)) { if (!session.users().removeFederatedIdentity(realm, user, provider)) {
throw new NotFoundException("Link not found"); throw new NotFoundException("Link not found");
} }
@ -525,13 +518,11 @@ public class UsersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<Map<String, Object>> getConsents(final @PathParam("id") String id) { public List<Map<String, Object>> getConsents(final @PathParam("id") String id) {
auth.requireView();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireView(user);
List<Map<String, Object>> result = new LinkedList<>(); List<Map<String, Object>> result = new LinkedList<>();
Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user); Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
@ -580,14 +571,16 @@ public class UsersResource {
@DELETE @DELETE
@NoCache @NoCache
public void revokeConsent(final @PathParam("id") String id, final @PathParam("client") String clientId) { public void revokeConsent(final @PathParam("id") String id, final @PathParam("client") String clientId) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
ClientModel client = realm.getClientByClientId(clientId); ClientModel client = realm.getClientByClientId(clientId);
if (client == null) {
throw new NotFoundException("Client not found");
}
boolean revokedConsent = session.users().revokeConsentForClient(realm, user.getId(), client.getId()); boolean revokedConsent = session.users().revokeConsentForClient(realm, user.getId(), client.getId());
boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client); boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client);
@ -612,12 +605,11 @@ public class UsersResource {
@Path("{id}/logout") @Path("{id}/logout")
@POST @POST
public void logout(final @PathParam("id") String id) { public void logout(final @PathParam("id") String id) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user); List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
for (UserSessionModel userSession : userSessions) { for (UserSessionModel userSession : userSessions) {
@ -635,12 +627,11 @@ public class UsersResource {
@DELETE @DELETE
@NoCache @NoCache
public Response deleteUser(final @PathParam("id") String id) { public Response deleteUser(final @PathParam("id") String id) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
boolean removed = new UserManager(session).removeUser(realm, user); boolean removed = new UserManager(session).removeUser(realm, user);
if (removed) { if (removed) {
@ -675,7 +666,7 @@ public class UsersResource {
@QueryParam("username") String username, @QueryParam("username") String username,
@QueryParam("first") Integer firstResult, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) { @QueryParam("max") Integer maxResults) {
auth.requireView(); auth.users().requireQuery();
firstResult = firstResult != null ? firstResult : -1; firstResult = firstResult != null ? firstResult : -1;
maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS; maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
@ -703,7 +694,9 @@ public class UsersResource {
userModels = session.users().getUsers(realm, firstResult, maxResults, false); userModels = session.users().getUsers(realm, firstResult, maxResults, false);
} }
boolean canViewGlobal = auth.users().canView();
for (UserModel user : userModels) { for (UserModel user : userModels) {
if (!canViewGlobal && !auth.users().canView(user)) continue;
results.add(ModelToRepresentation.toRepresentation(session, realm, user)); results.add(ModelToRepresentation.toRepresentation(session, realm, user));
} }
return results; return results;
@ -714,21 +707,23 @@ public class UsersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Integer getUsersCount() { public Integer getUsersCount() {
auth.requireView(); auth.users().requireView();
return session.users().getUsersCount(realm); return session.users().getUsersCount(realm);
} }
@Path("{id}/role-mappings") @Path("{id}/role-mappings")
public RoleMapperResource getRoleMappings(@PathParam("id") String id) { public RoleMapperResource getRoleMappings(@PathParam("id") String id) {
auth.init(RealmAuth.Resource.USER);
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
RoleMapperResource resource = new RoleMapperResource(realm, auth, user, adminEvent); if (user == null) {
resource.setManageCheck(() -> { throw new NotFoundException("User not found");
return new MgmtPermissions(session, realm, auth.getAuth()).users().canManage(); }
});
AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.users().requireManage(user);
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.users().requireView(user);
RoleMapperResource resource = new RoleMapperResource(realm, auth, user, adminEvent, manageCheck, viewCheck);
ResteasyProviderFactory.getInstance().injectProperties(resource); ResteasyProviderFactory.getInstance().injectProperties(resource);
return resource; return resource;
@ -744,12 +739,12 @@ public class UsersResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void disableCredentialType(@PathParam("id") String id, List<String> credentialTypes) { public void disableCredentialType(@PathParam("id") String id, List<String> credentialTypes) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
if (credentialTypes == null) return; if (credentialTypes == null) return;
for (String type : credentialTypes) { for (String type : credentialTypes) {
session.userCredentialManager().disableCredentialType(realm, user, type); session.userCredentialManager().disableCredentialType(realm, user, type);
@ -771,12 +766,12 @@ public class UsersResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void resetPassword(@PathParam("id") String id, CredentialRepresentation pass) { public void resetPassword(@PathParam("id") String id, CredentialRepresentation pass) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
if (pass == null || pass.getValue() == null || !CredentialRepresentation.PASSWORD.equals(pass.getType())) { if (pass == null || pass.getValue() == null || !CredentialRepresentation.PASSWORD.equals(pass.getType())) {
throw new BadRequestException("No password provided"); throw new BadRequestException("No password provided");
} }
@ -792,7 +787,7 @@ public class UsersResource {
} catch (ReadOnlyException mre) { } catch (ReadOnlyException mre) {
throw new BadRequestException("Can't reset password as account is read only"); throw new BadRequestException("Can't reset password as account is read only");
} catch (ModelException e) { } catch (ModelException e) {
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale()); Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(e.getMessage(), MessageFormat.format(messages.getProperty(e.getMessage(), e.getMessage()), e.getParameters()), throw new ErrorResponseException(e.getMessage(), MessageFormat.format(messages.getProperty(e.getMessage(), e.getMessage()), e.getParameters()),
Status.BAD_REQUEST); Status.BAD_REQUEST);
} }
@ -810,13 +805,15 @@ public class UsersResource {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void removeTotp(@PathParam("id") String id) { public void removeTotp(@PathParam("id") String id) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
session.userCredentialManager().disableCredentialType(realm, user, CredentialModel.OTP); session.userCredentialManager().disableCredentialType(realm, user, CredentialModel.OTP);
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success(); adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
} }
@ -870,12 +867,12 @@ public class UsersResource {
@QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId, @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId,
@QueryParam("lifespan") Integer lifespan, @QueryParam("lifespan") Integer lifespan,
List<String> actions) { List<String> actions) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
return ErrorResponse.error("User not found", Response.Status.NOT_FOUND); return ErrorResponse.error("User not found", Response.Status.NOT_FOUND);
} }
auth.users().requireManage(user);
if (user.getEmail() == null) { if (user.getEmail() == null) {
return ErrorResponse.error("User email missing", Response.Status.BAD_REQUEST); return ErrorResponse.error("User email missing", Response.Status.BAD_REQUEST);
@ -964,12 +961,12 @@ public class UsersResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<GroupRepresentation> groupMembership(@PathParam("id") String id) { public List<GroupRepresentation> groupMembership(@PathParam("id") String id) {
auth.requireView();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireView(user);
List<GroupRepresentation> memberships = new LinkedList<>(); List<GroupRepresentation> memberships = new LinkedList<>();
for (GroupModel group : user.getGroups()) { for (GroupModel group : user.getGroups()) {
memberships.add(ModelToRepresentation.toRepresentation(group, false)); memberships.add(ModelToRepresentation.toRepresentation(group, false));
@ -981,12 +978,13 @@ public class UsersResource {
@Path("{id}/groups/{groupId}") @Path("{id}/groups/{groupId}")
@NoCache @NoCache
public void removeMembership(@PathParam("id") String id, @PathParam("groupId") String groupId) { public void removeMembership(@PathParam("id") String id, @PathParam("groupId") String groupId) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
GroupModel group = session.realms().getGroupById(groupId, realm); GroupModel group = session.realms().getGroupById(groupId, realm);
if (group == null) { if (group == null) {
throw new NotFoundException("Group not found"); throw new NotFoundException("Group not found");
@ -998,7 +996,7 @@ public class UsersResource {
adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success(); adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
} }
} catch (ModelException me) { } catch (ModelException me) {
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale()); Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()), throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),
Response.Status.BAD_REQUEST); Response.Status.BAD_REQUEST);
} }
@ -1008,12 +1006,12 @@ public class UsersResource {
@Path("{id}/groups/{groupId}") @Path("{id}/groups/{groupId}")
@NoCache @NoCache
public void joinGroup(@PathParam("id") String id, @PathParam("groupId") String groupId) { public void joinGroup(@PathParam("id") String id, @PathParam("groupId") String groupId) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(id, realm);
if (user == null) { if (user == null) {
throw new NotFoundException("User not found"); throw new NotFoundException("User not found");
} }
auth.users().requireManage(user);
GroupModel group = session.realms().getGroupById(groupId, realm); GroupModel group = session.realms().getGroupById(groupId, realm);
if (group == null) { if (group == null) {
throw new NotFoundException("Group not found"); throw new NotFoundException("Group not found");

View file

@ -0,0 +1,55 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.services.resources.admin.AdminAuth;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface AdminPermissionEvaluator {
RealmPermissionEvaluator realm();
AdminAuth adminAuth();
RolePermissionEvaluator roles();
UserPermissionEvaluator users();
ClientPermissionEvaluator clients();
GroupPermissionEvaluator groups();
/**
* Useful as a function pointer, i.e. RoleMapperResource is reused bewteen GroupResource and UserResource to manage role mappings.
* We don't know what type of resource we're managing here (user or group), so we don't know how to query the policy engine to determine
* if an action is allowed.
*
*/
interface PermissionCheck {
boolean evaluate();
}
/**
* Useful as a function pointer, i.e. RoleMapperResource is reused bewteen GroupResource and UserResource to manage role mappings.
* We don't know what type of resource we're managing here (user or group), so we don't know how to query the policy engine to determine
* if an action is allowed.
*
* throws appropriate exception if permission is deny
*
*/
interface RequirePermissionCheck {
void require();
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.authorization.model.ResourceServer;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface AdminPermissionManagement {
public static final String MANAGE_SCOPE = "manage";
public static final String VIEW_SCOPE = "view";
RolePermissionManagement roles();
UserPermissionManagement users();
GroupPermissionManagement groups();
ClientPermissionManagement clients();
ResourceServer realmResourceServer();
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.resources.admin.AdminAuth;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AdminPermissions {
public static AdminPermissionEvaluator evaluator(KeycloakSession session, RealmModel realm, AdminAuth auth) {
return new MgmtPermissions(session, realm, auth);
}
public static AdminPermissionEvaluator evaluator(KeycloakSession session, RealmModel realm, RealmModel adminsRealm, UserModel admin) {
return new MgmtPermissions(session, realm, adminsRealm, admin);
}
public static AdminPermissionManagement management(KeycloakSession session, RealmModel realm) {
return new MgmtPermissions(session, realm);
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientTemplateModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface ClientPermissionEvaluator {
boolean isPermissionsEnabled(ClientModel client);
void setPermissionsEnabled(ClientModel client, boolean enable);
boolean canManage();
void requireManage();
boolean canManageTemplates();
void requireManageTemplates();
boolean canView();
boolean canList();
boolean canViewTemplates();
void requireList();
boolean canListTemplates();
void requireView();
void requireViewTemplates();
boolean canManage(ClientModel client);
void requireManage(ClientModel client);
boolean canView(ClientModel client);
void requireView(ClientModel client);
boolean canManage(ClientTemplateModel template);
void requireManage(ClientTemplateModel template);
boolean canView(ClientTemplateModel template);
void requireView(ClientTemplateModel template);
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.models.ClientModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface ClientPermissionManagement {
boolean isPermissionsEnabled(ClientModel client);
void setPermissionsEnabled(ClientModel client, boolean enable);
}

View file

@ -0,0 +1,309 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.jboss.logging.Logger;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientTemplateModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.services.ForbiddenException;
import java.util.HashSet;
import java.util.Set;
/**
* Manages default policies for all users.
*
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionManagement {
private static final Logger logger = Logger.getLogger(ClientPermissions.class);
protected final KeycloakSession session;
protected final RealmModel realm;
protected final AuthorizationProvider authz;
protected final MgmtPermissions root;
public ClientPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
this.session = session;
this.realm = realm;
this.authz = authz;
this.root = root;
}
private String getResourceName(ClientModel client) {
return "group.resource." + client.getId();
}
private String getManagePermissionName(ClientModel client) {
return "manage.permission.client." + client.getId();
}
private String getViewPermissionName(ClientModel client) {
return "view.permission.client." + client.getId();
}
private void initialize(ClientModel client) {
ResourceServer server = root.findOrCreateResourceServer(client);
Scope manageScope = manageScope(server);
if (manageScope == null) {
authz.getStoreFactory().getScopeStore().create(AdminPermissionManagement.MANAGE_SCOPE, server);
}
Scope viewScope = viewScope(server);
if (manageScope == null) {
authz.getStoreFactory().getScopeStore().create(AdminPermissionManagement.VIEW_SCOPE, server);
}
String resourceName = getResourceName(client);
Resource resource = authz.getStoreFactory().getResourceStore().findByName(resourceName, server.getId());
if (resource == null) {
resource = authz.getStoreFactory().getResourceStore().create(resourceName, server, server.getClientId());
Set<Scope> scopeset = new HashSet<>();
scopeset.add(manageScope);
scopeset.add(viewScope);
resource.updateScopes(scopeset);
}
String managePermissionName = getManagePermissionName(client);
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
if (managePermission == null) {
RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_CLIENTS);
Policy manageClientsPolicy = root.roles().rolePolicy(server, role);
Helper.addScopePermission(authz, server, managePermissionName, resource, manageScope, manageClientsPolicy);
}
String viewPermissionName = getViewPermissionName(client);
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
if (viewPermission == null) {
RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.VIEW_CLIENTS);
Policy viewClientsPolicy = root.roles().rolePolicy(server, role);
Helper.addScopePermission(authz, server, viewPermissionName, resource, viewScope, viewClientsPolicy);
}
}
private void deletePermissions(ClientModel client) {
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) return;
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(getManagePermissionName(client), server.getId());
if (managePermission != null) {
authz.getStoreFactory().getPolicyStore().delete(managePermission.getId());
}
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(getViewPermissionName(client), server.getId());
if (viewPermission != null) {
authz.getStoreFactory().getPolicyStore().delete(viewPermission.getId());
}
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());;
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
}
@Override
public boolean isPermissionsEnabled(ClientModel client) {
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) return false;
return authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId()) != null;
}
@Override
public void setPermissionsEnabled(ClientModel client, boolean enable) {
if (enable) {
initialize(client);
} else {
deletePermissions(client);
}
}
private Scope manageScope(ResourceServer server) {
return authz.getStoreFactory().getScopeStore().findByName(AdminPermissionManagement.MANAGE_SCOPE, server.getId());
}
private Scope viewScope(ResourceServer server) {
return authz.getStoreFactory().getScopeStore().findByName(AdminPermissionManagement.VIEW_SCOPE, server.getId());
}
@Override
public boolean canList() {
return root.hasAnyAdminRole();
}
@Override
public void requireList() {
if (!canList()) {
throw new ForbiddenException();
}
}
@Override
public boolean canListTemplates() {
return root.hasAnyAdminRole();
}
public boolean canManageClientDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_CLIENTS);
}
public boolean canViewClientDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_CLIENTS, AdminRoles.VIEW_CLIENTS);
}
@Override
public boolean canManage() {
return canManageClientDefault();
}
@Override
public void requireManage() {
if (!canManage()) {
throw new ForbiddenException();
}
}
@Override
public boolean canView() {
return canManageClientDefault() || canViewClientDefault();
}
@Override
public void requireView() {
if (!canView()) {
throw new ForbiddenException();
}
}
@Override
public boolean canManage(ClientModel client) {
if (!root.isAdminSameRealm()) {
return canManage();
}
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) return canManage();
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
if (resource == null) return canManage();
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getManagePermissionName(client), server.getId());
if (policy == null) {
return canManage();
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canManage();
}
Scope scope = manageScope(server);
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireManage(ClientModel client) {
if (!canManage(client)) {
throw new ForbiddenException();
}
}
@Override
public boolean canView(ClientModel client) {
if (!root.isAdminSameRealm()) {
return canView();
}
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) return canView();
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
if (resource == null) return canView();
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getViewPermissionName(client), server.getId());
if (policy == null) {
return canView();
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canView();
}
Scope scope = viewScope(server);
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireView(ClientModel client) {
if (!canView(client)) {
throw new ForbiddenException();
}
}
// templates
@Override
public boolean canViewTemplates() {
return canView();
}
@Override
public boolean canManageTemplates() {
return canManageClientDefault();
}
@Override
public void requireManageTemplates() {
if (!canManageTemplates()) {
throw new ForbiddenException();
}
}
@Override
public void requireViewTemplates() {
if (!canViewTemplates()) {
throw new ForbiddenException();
}
}
@Override
public boolean canManage(ClientTemplateModel template) {
return canManageClientDefault();
}
@Override
public void requireManage(ClientTemplateModel template) {
if (!canManage(template)) {
throw new ForbiddenException();
}
}
@Override
public boolean canView(ClientTemplateModel template) {
return canViewClientDefault();
}
@Override
public void requireView(ClientTemplateModel template) {
if (!canView(template)) {
throw new ForbiddenException();
}
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.models.GroupModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface GroupPermissionEvaluator {
boolean canList();
void requireList();
boolean canManage(GroupModel group);
void requireManage(GroupModel group);
boolean canView(GroupModel group);
void requireView(GroupModel group);
boolean canManage();
void requireManage();
boolean canView();
void requireView();
boolean canViewMembers(GroupModel group);
void requireViewMembers(GroupModel group);
boolean canManageMembers(GroupModel group);
void requireManageMembers(GroupModel group);
}

View file

@ -0,0 +1,37 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.authorization.model.Policy;
import org.keycloak.models.GroupModel;
import org.keycloak.models.RoleModel;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface GroupPermissionManagement {
boolean isPermissionsEnabled(GroupModel group);
void setPermissionsEnabled(GroupModel group, boolean enable);
Policy viewMembersPermission(GroupModel group);
Policy manageMembersPermission(GroupModel group);
Policy viewPermissionGroup(GroupModel group);
Policy managePermissionGroup(GroupModel group);
}

View file

@ -0,0 +1,383 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.jboss.logging.Logger;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.ForbiddenException;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManagement {
private static final Logger logger = Logger.getLogger(GroupPermissions.class);
public static final String MAP_ROLE_SCOPE = "map-role";
public static final String MANAGE_MEMBERS_SCOPE = "manage.members";
public static final String VIEW_MEMBERS_SCOPE = "view.members";
protected final KeycloakSession session;
protected final RealmModel realm;
protected final AuthorizationProvider authz;
protected final MgmtPermissions root;
public GroupPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
this.session = session;
this.realm = realm;
this.authz = authz;
this.root = root;
}
private static String getGroupResourceName(GroupModel group) {
return "group.resource." + getGroupSuffix(group);
}
public static String getManagePermissionGroup(GroupModel group) {
return "manage.permission.group." + getGroupSuffix(group);
}
public static String getManageMembersPermissionGroup(GroupModel group) {
return "manage.members.permission.group." + getGroupSuffix(group);
}
public static String getGroupSuffix(GroupModel group) {
return ModelToRepresentation.buildGroupPath(group).replace('/', '.');
}
public static String getViewPermissionGroup(GroupModel group) {
return "view.permission.group." + getGroupSuffix(group);
}
public static String getViewMembersPermissionGroup(GroupModel group) {
return "view.members.permission.group." + getGroupSuffix(group);
}
private void initialize(GroupModel group) {
root.initializeRealmResourceServer();
root.initializeRealmDefaultScopes();
ResourceServer server = root.realmResourceServer();
Scope manageScope = root.realmManageScope();
Scope viewScope = root.realmViewScope();
Scope manageMembersScope = root.initializeRealmScope(MANAGE_MEMBERS_SCOPE);
Scope viewMembersScope = root.initializeRealmScope(VIEW_MEMBERS_SCOPE);
String groupResourceName = getGroupResourceName(group);
Resource groupResource = authz.getStoreFactory().getResourceStore().findByName(groupResourceName, server.getId());
if (groupResource == null) {
groupResource = authz.getStoreFactory().getResourceStore().create(groupResourceName, server, server.getClientId());
Set<Scope> scopeset = new HashSet<>();
scopeset.add(manageScope);
scopeset.add(viewScope);
groupResource.updateScopes(scopeset);
}
String managePermissionName = getManagePermissionGroup(group);
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
if (managePermission == null) {
Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
Helper.addScopePermission(authz, server, managePermissionName, groupResource, manageScope, manageUsersPolicy);
}
String viewPermissionName = getManagePermissionGroup(group);
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
if (viewPermission == null) {
Policy viewUsersPolicy = root.roles().viewUsersPolicy(server);
Helper.addScopePermission(authz, server, viewPermissionName, groupResource, viewScope, viewUsersPolicy);
}
String manageMembersPermissionName = getManageMembersPermissionGroup(group);
Policy manageMembersPermission = authz.getStoreFactory().getPolicyStore().findByName(manageMembersPermissionName, server.getId());
if (manageMembersPermission == null) {
Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
Helper.addScopePermission(authz, server, manageMembersPermissionName, groupResource, manageMembersScope, manageUsersPolicy);
}
String viewMembersPermissionName = getViewMembersPermissionGroup(group);
Policy viewMembersPermission = authz.getStoreFactory().getPolicyStore().findByName(viewMembersPermissionName, server.getId());
if (viewMembersPermission == null) {
Policy viewUsersPolicy = root.roles().viewUsersPolicy(server);
Helper.addScopePermission(authz, server, viewMembersPermissionName, groupResource, viewMembersScope, viewUsersPolicy);
}
}
@Override
public boolean canList() {
return root.hasOneAdminRole(AdminRoles.VIEW_USERS, AdminRoles.MANAGE_USERS);
}
@Override
public void requireList() {
if (!canList()) {
throw new ForbiddenException();
}
}
@Override
public boolean isPermissionsEnabled(GroupModel group) {
ResourceServer server = root.realmResourceServer();
if (server == null) return false;
return authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId()) != null;
}
private Resource groupResource(GroupModel group) {
ResourceServer server = root.realmResourceServer();
if (server == null) return null;
String groupResourceName = getGroupResourceName(group);
return authz.getStoreFactory().getResourceStore().findByName(groupResourceName, server.getId());
}
@Override
public void setPermissionsEnabled(GroupModel group, boolean enable) {
if (enable) {
initialize(group);
} else {
deletePermissions(group);
}
}
private void deletePermissions(GroupModel group) {
ResourceServer server = root.realmResourceServer();
if (server == null) return;
Policy managePermission = managePermissionGroup(group);
if (managePermission != null) {
authz.getStoreFactory().getPolicyStore().delete(managePermission.getId());
}
Policy viewPermission = viewPermissionGroup(group);
if (viewPermission != null) {
authz.getStoreFactory().getPolicyStore().delete(viewPermission.getId());
}
Policy manageMembersPermission = manageMembersPermission(group);
if (manageMembersPermission != null) {
authz.getStoreFactory().getPolicyStore().delete(manageMembersPermission.getId());
}
Policy viewMembersPermission = viewMembersPermission(group);
if (manageMembersPermission == null) {
authz.getStoreFactory().getPolicyStore().delete(viewMembersPermission.getId());
}
Resource resource = groupResource(group);
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
}
@Override
public Policy viewMembersPermission(GroupModel group) {
ResourceServer server = root.realmResourceServer();
if (server == null) return null;
String viewMembersPermissionName = getViewMembersPermissionGroup(group);
return authz.getStoreFactory().getPolicyStore().findByName(viewMembersPermissionName, server.getId());
}
@Override
public Policy manageMembersPermission(GroupModel group) {
ResourceServer server = root.realmResourceServer();
if (server == null) return null;
String manageMembersPermissionName = getManageMembersPermissionGroup(group);
return authz.getStoreFactory().getPolicyStore().findByName(manageMembersPermissionName, server.getId());
}
@Override
public Policy viewPermissionGroup(GroupModel group) {
ResourceServer server = root.realmResourceServer();
if (server == null) return null;
String viewPermissionName = getViewPermissionGroup(group);
return authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
}
@Override
public Policy managePermissionGroup(GroupModel group) {
ResourceServer server = root.realmResourceServer();
if (server == null) return null;
String managePermissionName = getManagePermissionGroup(group);
return authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
}
@Override
public boolean canManage(GroupModel group) {
if (!root.isAdminSameRealm()) {
return canManage();
}
ResourceServer server = root.realmResourceServer();
if (server == null) return canManage();
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return canManage();
Policy policy = managePermissionGroup(group);
if (policy == null) {
return canManage();
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canManage();
}
Scope scope = root.realmManageScope();
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireManage(GroupModel group) {
if (!canManage(group)) {
throw new ForbiddenException();
}
}
@Override
public boolean canView(GroupModel group) {
if (!root.isAdminSameRealm()) {
return canView();
}
ResourceServer server = root.realmResourceServer();
if (server == null) return canView();
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return canView();
Policy policy = viewPermissionGroup(group);
if (policy == null) {
return canView();
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then abort
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canView();
}
Scope scope = root.realmViewScope();
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireView(GroupModel group) {
if (!canView(group)) {
throw new ForbiddenException();
}
}
@Override
public boolean canManage() {
return root.users().canManageDefault();
}
@Override
public void requireManage() {
if (!canManage()) {
throw new ForbiddenException();
}
}
@Override
public boolean canView() {
return root.users().canViewDefault();
}
@Override
public void requireView() {
if (!canView()) {
throw new ForbiddenException();
}
}
@Override
public boolean canViewMembers(GroupModel group) {
if (!root.isAdminSameRealm()) {
return root.users().canView();
}
ResourceServer server = root.realmResourceServer();
if (server == null) return root.users().canView();
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return root.users().canView();
Policy policy = viewMembersPermission(group);
if (policy == null) {
return root.users().canView();
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return root.users().canView();
}
Scope scope = authz.getStoreFactory().getScopeStore().findByName(VIEW_MEMBERS_SCOPE, server.getId());
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireViewMembers(GroupModel group) {
if (!canViewMembers(group)) {
throw new ForbiddenException();
}
}
@Override
public boolean canManageMembers(GroupModel group) {
if (!root.isAdminSameRealm()) {
return root.users().canManage();
}
ResourceServer server = root.realmResourceServer();
if (server == null) return root.users().canManage();
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return root.users().canManage();
Policy policy = manageMembersPermission(group);
if (policy == null) {
return root.users().canManage();
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return root.users().canManage();
}
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MANAGE_MEMBERS_SCOPE, server.getId());
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireManageMembers(GroupModel group) {
if (!canManageMembers(group)) {
throw new ForbiddenException();
}
}
}

View file

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.authorization.admin.permissions; package org.keycloak.services.resources.admin.permissions;
import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.model.Policy;
@ -35,7 +35,7 @@ import java.util.Map;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class Helper { class Helper {
public static Policy addScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope, Policy policy) { public static Policy addScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope, Policy policy) {
ScopePermissionRepresentation representation = new ScopePermissionRepresentation(); ScopePermissionRepresentation representation = new ScopePermissionRepresentation();

View file

@ -0,0 +1,274 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.AuthorizationProviderFactory;
import org.keycloak.authorization.Decision;
import org.keycloak.authorization.common.DefaultEvaluationContext;
import org.keycloak.authorization.common.KeycloakIdentity;
import org.keycloak.authorization.common.UserModelIdentity;
import org.keycloak.authorization.identity.Identity;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.permission.ResourcePermission;
import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
import org.keycloak.authorization.policy.evaluation.DecisionResult;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.util.Permissions;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.admin.AdminAuth;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManagement {
private static final Logger logger = Logger.getLogger(MgmtPermissions.class);
protected RealmModel realm;
protected KeycloakSession session;
protected AuthorizationProvider authz;
protected AdminAuth auth;
protected Identity identity;
protected UserModel admin;
protected RealmModel adminsRealm;
protected ResourceServer realmResourceServer;
protected UserPermissions users;
protected GroupPermissions groups;
protected RealmPermissions realmPermissions;
protected ClientPermissions clientPermissions;
MgmtPermissions(KeycloakSession session, RealmModel realm) {
this.session = session;
this.realm = realm;
KeycloakSessionFactory keycloakSessionFactory = session.getKeycloakSessionFactory();
AuthorizationProviderFactory factory = (AuthorizationProviderFactory) keycloakSessionFactory.getProviderFactory(AuthorizationProvider.class);
this.authz = factory.create(session, realm);
}
MgmtPermissions(KeycloakSession session, RealmModel realm, AdminAuth auth) {
this(session, realm);
this.auth = auth;
this.admin = auth.getUser();
this.adminsRealm = auth.getRealm();
if (!auth.getRealm().equals(realm)
&& !auth.getRealm().equals(new RealmManager(session).getKeycloakAdminstrationRealm())) {
throw new ForbiddenException();
}
if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)) {
this.identity = new UserModelIdentity(auth.getRealm(), auth.getUser());
} else {
this.identity = new KeycloakIdentity(auth.getToken(), session);
}
}
MgmtPermissions(KeycloakSession session, RealmModel realm, RealmModel adminsRealm, UserModel admin) {
this(session, realm);
this.admin = admin;
this.adminsRealm = adminsRealm;
this.identity = new UserModelIdentity(realm, admin);
}
public ClientModel getRealmManagementClient() {
ClientModel client = null;
if (realm.getName().equals(Config.getAdminRealm())) {
client = realm.getClientByClientId(Config.getAdminRealm() + "-realm");
} else {
client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
}
return client;
}
public boolean hasAnyAdminRole() {
return hasOneAdminRole(AdminRoles.ALL_REALM_ROLES);
}
public boolean hasOneAdminRole(String... adminRoles) {
String clientId;
RealmManager realmManager = new RealmManager(session);
if (adminsRealm.equals(realmManager.getKeycloakAdminstrationRealm())) {
clientId = realm.getMasterAdminClient().getClientId();
} else {
clientId = realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())).getClientId();
}
for (String adminRole : adminRoles) {
if (identity.hasClientRole(clientId, adminRole)) return true;
}
return false;
}
public boolean isAdminSameRealm() {
return auth == null || realm.getId().equals(auth.getRealm().getId());
}
@Override
public AdminAuth adminAuth() {
return auth;
}
public Identity identity() {
return identity;
}
public UserModel admin() {
return admin;
}
@Override
public RolePermissions roles() {
return new RolePermissions(session, realm, authz, this);
}
@Override
public UserPermissions users() {
if (users != null) return users;
users = new UserPermissions(session, realm, authz, this);
return users;
}
@Override
public RealmPermissions realm() {
if (realmPermissions != null) return realmPermissions;
realmPermissions = new RealmPermissions(session, realm, authz, this);
return realmPermissions;
}
@Override
public ClientPermissions clients() {
if (clientPermissions != null) return clientPermissions;
clientPermissions = new ClientPermissions(session, realm, authz, this);
return clientPermissions;
}
@Override
public GroupPermissions groups() {
if (groups != null) return groups;
groups = new GroupPermissions(session, realm, authz, this);
return groups;
}
public ResourceServer findOrCreateResourceServer(ClientModel client) {
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) {
server = authz.getStoreFactory().getResourceServerStore().create(client.getId());
}
return server;
}
@Override
public ResourceServer realmResourceServer() {
if (realmResourceServer != null) return realmResourceServer;
ResourceServerStore resourceServerStore = authz.getStoreFactory().getResourceServerStore();
ClientModel client = getRealmManagementClient();
realmResourceServer = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
return realmResourceServer;
}
public ResourceServer initializeRealmResourceServer() {
if (realmResourceServer != null) return realmResourceServer;
ClientModel client = getRealmManagementClient();
return findOrCreateResourceServer(client);
}
protected Scope manageScope;
protected Scope viewScope;
public void initializeRealmDefaultScopes() {
ResourceServer server = initializeRealmResourceServer();
manageScope = initializeRealmScope(MgmtPermissions.MANAGE_SCOPE);
viewScope = initializeRealmScope(MgmtPermissions.VIEW_SCOPE);
}
public Scope initializeRealmScope(String name) {
ResourceServer server = initializeRealmResourceServer();
Scope scope = authz.getStoreFactory().getScopeStore().findByName(name, server.getId());
if (scope == null) {
scope = authz.getStoreFactory().getScopeStore().create(name, server);
}
return scope;
}
public Scope realmManageScope() {
if (manageScope != null) return manageScope;
manageScope = realmScope(MgmtPermissions.MANAGE_SCOPE);
return manageScope;
}
public Scope realmViewScope() {
if (viewScope != null) return viewScope;
viewScope = realmScope(MgmtPermissions.VIEW_SCOPE);
return viewScope;
}
public Scope realmScope(String scope) {
ResourceServer server = realmResourceServer();
if (server == null) return null;
return authz.getStoreFactory().getScopeStore().findByName(scope, server.getId());
}
public boolean evaluatePermission(Resource resource, Scope scope, ResourceServer resourceServer) {
Identity identity = identity();
if (identity == null) {
throw new RuntimeException("Identity of admin is not set for permission query");
}
RealmModel oldRealm = session.getContext().getRealm();
try {
session.getContext().setRealm(realm);
EvaluationContext context = new DefaultEvaluationContext(identity, session);
DecisionResult decisionCollector = new DecisionResult();
List<ResourcePermission> permissions = Permissions.permission(resourceServer, resource, scope);
PermissionEvaluator from = authz.evaluators().from(permissions, context);
from.evaluate(decisionCollector);
if (!decisionCollector.completed()) {
logger.error("Failed to run permission check", decisionCollector.getError());
return false;
}
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
} finally {
session.getContext().setRealm(oldRealm);
}
}
}

View file

@ -15,24 +15,21 @@
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.services.resources.admin; package org.keycloak.services.resources.admin.permissions;
import org.keycloak.models.AdminRoles; import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ImpersonationConstants; import org.keycloak.models.ImpersonationConstants;
import org.keycloak.services.ForbiddenException; import org.keycloak.services.ForbiddenException;
import org.keycloak.services.resources.admin.AdminAuth;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
public class RealmAuth { class RealmAuth {
private Resource resource; private AdminAuth.Resource resource;
public enum Resource {
CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION, AUTHORIZATION
}
private AdminAuth auth; private AdminAuth auth;
private ClientModel realmAdminApp; private ClientModel realmAdminApp;
@ -42,7 +39,7 @@ public class RealmAuth {
this.realmAdminApp = realmAdminApp; this.realmAdminApp = realmAdminApp;
} }
public RealmAuth init(Resource resource) { public RealmAuth init(AdminAuth.Resource resource) {
this.resource = resource; this.resource = resource;
return this; return this;
} }
@ -52,11 +49,15 @@ public class RealmAuth {
} }
public void requireAny() { public void requireAny() {
if (!auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) { if (!hasAny()) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
} }
public boolean hasAny() {
return auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES);
}
public boolean hasView() { public boolean hasView() {
return auth.hasOneOfAppRole(realmAdminApp, getViewRole(resource), getManageRole(resource)); return auth.hasOneOfAppRole(realmAdminApp, getViewRole(resource), getManageRole(resource));
} }
@ -77,7 +78,7 @@ public class RealmAuth {
} }
} }
private String getViewRole(Resource resource) { private String getViewRole(AdminAuth.Resource resource) {
switch (resource) { switch (resource) {
case CLIENT: case CLIENT:
return AdminRoles.VIEW_CLIENTS; return AdminRoles.VIEW_CLIENTS;
@ -96,7 +97,7 @@ public class RealmAuth {
} }
} }
private String getManageRole(Resource resource) { private String getManageRole(AdminAuth.Resource resource) {
switch (resource) { switch (resource) {
case CLIENT: case CLIENT:
return AdminRoles.MANAGE_CLIENTS; return AdminRoles.MANAGE_CLIENTS;

View file

@ -0,0 +1,59 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface RealmPermissionEvaluator {
boolean canListRealm();
void requireViewRealmNameList();
boolean canManageRealm();
void requireManageRealm();
boolean canViewRealm();
void requireViewRealm();
boolean canManageIdentityProviders();
boolean canViewIdentityProviders();
void requireViewIdentityProviders();
void requireManageIdentityProviders();
boolean canManageAuthorization();
boolean canViewAuthorization();
void requireManageAuthorization();
void requireViewAuthorization();
boolean canManageEvents();
void requireManageEvents();
boolean canViewEvents();
void requireViewEvents();
}

View file

@ -0,0 +1,188 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.jboss.logging.Logger;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.ForbiddenException;
/**
* Manages default policies for all users.
*
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
class RealmPermissions implements RealmPermissionEvaluator {
private static final Logger logger = Logger.getLogger(RealmPermissions.class);
protected final KeycloakSession session;
protected final RealmModel realm;
protected final AuthorizationProvider authz;
protected final MgmtPermissions root;
public RealmPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
this.session = session;
this.realm = realm;
this.authz = authz;
this.root = root;
}
public boolean canManageRealmDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_REALM);
}
public boolean canViewRealmDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_REALM, AdminRoles.VIEW_REALM);
}
public boolean canManageIdentityProvidersDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_IDENTITY_PROVIDERS);
}
public boolean canViewIdentityProvidersDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_IDENTITY_PROVIDERS, AdminRoles.VIEW_IDENTITY_PROVIDERS);
}
public boolean canManageAuthorizationDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_AUTHORIZATION);
}
public boolean canViewAuthorizationDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_AUTHORIZATION, AdminRoles.VIEW_AUTHORIZATION);
}
public boolean canManageEventsDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_EVENTS);
}
public boolean canViewEventsDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_EVENTS, AdminRoles.VIEW_EVENTS);
}
@Override
public boolean canListRealm() {
return root.hasAnyAdminRole();
}
@Override
public void requireViewRealmNameList() {
if (!canListRealm()) {
throw new ForbiddenException();
}
}
@Override
public boolean canManageRealm() {
return canManageRealmDefault();
}
@Override
public void requireManageRealm() {
if (!canManageRealm()) {
throw new ForbiddenException();
}
}
@Override
public boolean canViewRealm() {
return canViewRealmDefault();
}
@Override
public void requireViewRealm() {
if (!canViewRealm()) {
throw new ForbiddenException();
}
}
@Override
public boolean canManageIdentityProviders() {
return canManageIdentityProvidersDefault();
}
@Override
public boolean canViewIdentityProviders() {
return canViewIdentityProvidersDefault();
}
@Override
public void requireViewIdentityProviders() {
if (!canViewIdentityProviders()) {
throw new ForbiddenException();
}
}
@Override
public void requireManageIdentityProviders() {
if (!canManageIdentityProviders()) {
throw new ForbiddenException();
}
}
@Override
public boolean canManageAuthorization() {
return canManageAuthorizationDefault();
}
@Override
public boolean canViewAuthorization() {
return canViewAuthorizationDefault();
}
@Override
public void requireManageAuthorization() {
if (!canManageEvents()) {
throw new ForbiddenException();
}
}
@Override
public void requireViewAuthorization() {
if (!canManageEvents()) {
throw new ForbiddenException();
}
}
@Override
public boolean canManageEvents() {
return canManageEventsDefault();
}
@Override
public void requireManageEvents() {
if (!canManageEvents()) {
throw new ForbiddenException();
}
}
@Override
public boolean canViewEvents() {
return canViewEventsDefault();
}
@Override
public void requireViewEvents() {
if (!canViewEvents()) {
throw new ForbiddenException();
}
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface RolePermissionEvaluator {
boolean canList(RoleContainerModel container);
void requireList(RoleContainerModel container);
boolean canMapRole(RoleModel role);
void requireMapRole(RoleModel role);
boolean canManage(RoleModel role);
void requireManage(RoleModel role);
boolean canView(RoleModel role);
void requireView(RoleModel role);
boolean canMapClientScope(RoleModel role);
void requireMapClientScope(RoleModel role);
boolean canMapComposite(RoleModel role);
void requireMapComposite(RoleModel role);
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface RolePermissionManagement {
public static final String MAP_ROLE_SCOPE = "map-role";
public static final String MAP_ROLE_CLIENT_SCOPE_SCOPE = "map-role-client-scope";
public static final String MAP_ROLE_COMPOSITE_SCOPE = "map-role-composite";
boolean isPermissionsEnabled(RoleModel role);
void setPermissionsEnabled(RoleModel role, boolean enable);
Map<String, String> getPermissions(RoleModel role);
Policy mapRolePermission(RoleModel role);
Policy mapCompositePermission(RoleModel role);
Policy mapClientScopePermission(RoleModel role);
Resource resource(RoleModel role);
ResourceServer resourceServer(RoleModel role);
Policy manageUsersPolicy(ResourceServer server);
Policy viewUsersPolicy(ResourceServer server);
Policy rolePolicy(ResourceServer server, RoleModel role);
}

View file

@ -0,0 +1,378 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.jboss.logging.Logger;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.services.ForbiddenException;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
class RolePermissions implements RolePermissionEvaluator, RolePermissionManagement {
private static final Logger logger = Logger.getLogger(RolePermissions.class);
protected final KeycloakSession session;
protected final RealmModel realm;
protected final AuthorizationProvider authz;
protected final MgmtPermissions root;
public RolePermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
this.session = session;
this.realm = realm;
this.authz = authz;
this.root = root;
}
@Override
public boolean isPermissionsEnabled(RoleModel role) {
return mapRolePermission(role) != null;
}
@Override
public void setPermissionsEnabled(RoleModel role, boolean enable) {
if (enable) {
ResourceServer server = getResourceServer(role);
if (authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId()) != null) {
return;
}
createResource(role);
} else {
ResourceServer server = resourceServer(role);
if (server == null) return;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), server.getId());
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
}
}
@Override
public Map<String, String> getPermissions(RoleModel role) {
Map<String, String> scopes = new HashMap<>();
scopes.put(RolePermissionManagement.MAP_ROLE_SCOPE, mapRolePermission(role).getId());
scopes.put(RolePermissionManagement.MAP_ROLE_CLIENT_SCOPE_SCOPE, mapClientScopePermission(role).getId());
scopes.put(RolePermissionManagement.MAP_ROLE_COMPOSITE_SCOPE, mapCompositePermission(role).getId());
return scopes;
}
@Override
public Policy mapRolePermission(RoleModel role) {
ResourceServer server = resourceServer(role);
if (server == null) return null;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
if (resource == null) return null;
return authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), server.getId());
}
@Override
public Policy mapCompositePermission(RoleModel role) {
ResourceServer server = resourceServer(role);
if (server == null) return null;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
if (resource == null) return null;
return authz.getStoreFactory().getPolicyStore().findByName(getMapCompositePermissionName(role), server.getId());
}
@Override
public Policy mapClientScopePermission(RoleModel role) {
ResourceServer server = resourceServer(role);
if (server == null) return null;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
if (resource == null) return null;
return authz.getStoreFactory().getPolicyStore().findByName(getMapClientScopePermissionName(role), server.getId());
}
@Override
public Resource resource(RoleModel role) {
ResourceStore resourceStore = authz.getStoreFactory().getResourceStore();
ResourceServer server = resourceServer(role);
if (server == null) return null;
return resourceStore.findByName(getRoleResourceName(role), server.getId());
}
@Override
public ResourceServer resourceServer(RoleModel role) {
ClientModel client = getRoleClient(role);
return authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
}
/**
* Is admin allowed to map this role?
*
* @param role
* @return
*/
@Override
public boolean canMapRole(RoleModel role) {
if (!root.isAdminSameRealm()) {
return root.users().canManage();
}
if (!isPermissionsEnabled(role)){
return root.users().canManage();
}
ResourceServer resourceServer = getResourceServer(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), resourceServer.getId());
if (policy.getAssociatedPolicies().isEmpty()) {
return root.users().canManage(); // if no policies applied, just do default
}
Resource roleResource = resource(role);
Scope mapRoleScope = getMapRoleScope(resourceServer);
return root.evaluatePermission(roleResource, mapRoleScope, resourceServer);
}
@Override
public void requireMapRole(RoleModel role) {
if (!canMapRole(role)) {
throw new ForbiddenException();
}
}
@Override
public boolean canList(RoleContainerModel container) {
return root.hasAnyAdminRole();
}
@Override
public void requireList(RoleContainerModel container) {
if (!canList(container)) {
throw new ForbiddenException();
}
}
@Override
public boolean canMapComposite(RoleModel role) {
if (!root.isAdminSameRealm()) {
return canManage(role);
}
if (!isPermissionsEnabled(role)){
return canManage(role);
}
ResourceServer resourceServer = getResourceServer(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapCompositePermissionName(role), resourceServer.getId());
if (policy.getAssociatedPolicies().isEmpty()) {
return canManage(role);
}
Resource roleResource = resource(role);
Scope scope = getMapCompositeScope(resourceServer);
return root.evaluatePermission(roleResource, scope, resourceServer);
}
@Override
public void requireMapComposite(RoleModel role) {
if (!canMapComposite(role)) {
throw new ForbiddenException();
}
}
@Override
public boolean canMapClientScope(RoleModel role) {
if (!root.isAdminSameRealm()) {
return root.clients().canManage();
}
if (!isPermissionsEnabled(role)){
return root.clients().canManage();
}
ResourceServer resourceServer = getResourceServer(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapClientScopePermissionName(role), resourceServer.getId());
if (policy.getAssociatedPolicies().isEmpty()) {
return root.clients().canManage();
}
Resource roleResource = resource(role);
Scope scope = getMapClientScope(resourceServer);
return root.evaluatePermission(roleResource, scope, resourceServer);
}
@Override
public void requireMapClientScope(RoleModel role) {
if (!canMapClientScope(role)) {
throw new ForbiddenException();
}
}
@Override
public boolean canManage(RoleModel role) {
if (role.getContainer() instanceof RealmModel) {
return root.realm().canManageRealm();
} else if (role.getContainer() instanceof ClientModel) {
ClientModel client = (ClientModel)role.getContainer();
return root.clients().canManage(client);
}
return false;
}
@Override
public void requireManage(RoleModel role) {
if (!canManage(role)) {
throw new ForbiddenException();
}
}
@Override
public boolean canView(RoleModel role) {
if (role.getContainer() instanceof RealmModel) {
return root.realm().canViewRealm();
} else if (role.getContainer() instanceof ClientModel) {
ClientModel client = (ClientModel)role.getContainer();
return root.clients().canView(client);
}
return false;
}
@Override
public void requireView(RoleModel role) {
if (!canView(role)) {
throw new ForbiddenException();
}
}
private ClientModel getRoleClient(RoleModel role) {
ClientModel client = null;
if (role.getContainer() instanceof ClientModel) {
client = (ClientModel)role.getContainer();
} else {
client = root.getRealmManagementClient();
}
return client;
}
@Override
public Policy manageUsersPolicy(ResourceServer server) {
RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_USERS);
return rolePolicy(server, role);
}
@Override
public Policy viewUsersPolicy(ResourceServer server) {
RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.VIEW_USERS);
return rolePolicy(server, role);
}
@Override
public Policy rolePolicy(ResourceServer server, RoleModel role) {
String policyName = Helper.getRolePolicyName(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(policyName, server.getId());
if (policy != null) return policy;
return Helper.createRolePolicy(authz, server, role, policyName);
}
private Scope getMapRoleScope(ResourceServer server) {
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_SCOPE, server.getId());
if (scope == null) {
scope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_SCOPE, server);
}
return scope;
}
private Scope getMapClientScope(ResourceServer server) {
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_CLIENT_SCOPE_SCOPE, server.getId());
if (scope == null) {
scope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_CLIENT_SCOPE_SCOPE, server);
}
return scope;
}
private Scope getMapCompositeScope(ResourceServer server) {
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_COMPOSITE_SCOPE, server.getId());
if (scope == null) {
scope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_COMPOSITE_SCOPE, server);
}
return scope;
}
private Resource createResource(RoleModel role) {
ResourceServer server = getResourceServer(role);
Resource resource = authz.getStoreFactory().getResourceStore().create(getRoleResourceName(role), server, server.getClientId());
resource.setType("Role");
Scope mapRoleScope = getMapRoleScope(server);
Policy policy = manageUsersPolicy(server);
Helper.addScopePermission(authz, server, getMapRolePermissionName(role), resource, mapRoleScope, policy);
Scope mapClientScope = getMapClientScope(server);
RoleModel mngClients = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_CLIENTS);
Policy mngClientsPolicy = rolePolicy(server, mngClients);
Helper.addScopePermission(authz, server, getMapClientScopePermissionName(role), resource, mapClientScope, mngClientsPolicy);
Scope mapCompositeScope = getMapCompositeScope(server);
if (role.getContainer() instanceof RealmModel) {
RoleModel mngRealm = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_REALM);
policy = rolePolicy(server, mngRealm);
} else {
policy = mngClientsPolicy;
}
Helper.addScopePermission(authz, server, getMapCompositePermissionName(role), resource, mapCompositeScope, policy);
return resource;
}
private String getMapRolePermissionName(RoleModel role) {
return MAP_ROLE_SCOPE + ".permission." + role.getName();
}
private String getMapClientScopePermissionName(RoleModel role) {
return MAP_ROLE_CLIENT_SCOPE_SCOPE + ".permission." + role.getName();
}
private String getMapCompositePermissionName(RoleModel role) {
return MAP_ROLE_CLIENT_SCOPE_SCOPE + ".permission." + role.getName();
}
private ResourceServer getResourceServer(RoleModel role) {
ClientModel client = getRoleClient(role);
return root.findOrCreateResourceServer(client);
}
private static String getRoleResourceName(RoleModel role) {
return "role.resource." + role.getName();
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.models.UserModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserPermissionEvaluator {
boolean canManage();
void requireManage();
boolean canManage(UserModel user);
void requireManage(UserModel user);
boolean canQuery();
void requireQuery();
boolean canView();
boolean canView(UserModel user);
void requireView(UserModel user);
void requireView();
boolean canImpersonate(UserModel user);
void requireImpersonate(UserModel user);
}

View file

@ -0,0 +1,41 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.models.RoleModel;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserPermissionManagement {
boolean isPermissionsEnabled();
void setPermissionsEnabled(boolean enable);
Map<String, String> getPermissions();
Resource resource();
Policy managePermission();
Policy viewPermission();
}

View file

@ -0,0 +1,382 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.resources.admin.permissions;
import org.jboss.logging.Logger;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.ImpersonationConstants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.ForbiddenException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Manages default policies for all users.
*
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
class UserPermissions implements UserPermissionEvaluator, UserPermissionManagement {
private static final Logger logger = Logger.getLogger(UserPermissions.class);
public static final String MANAGE_PERMISSION_USERS = "manage.permission.users";
public static final String VIEW_PERMISSION_USERS = "view.permission.users";
public static final String USERS_RESOURCE = "Users";
protected final KeycloakSession session;
protected final RealmModel realm;
protected final AuthorizationProvider authz;
protected final MgmtPermissions root;
public UserPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
this.session = session;
this.realm = realm;
this.authz = authz;
this.root = root;
}
private void initialize() {
root.initializeRealmResourceServer();
root.initializeRealmDefaultScopes();
ResourceServer server = root.realmResourceServer();
Scope manageScope = root.realmManageScope();
Scope viewScope = root.realmViewScope();
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (usersResource == null) {
usersResource = authz.getStoreFactory().getResourceStore().create(USERS_RESOURCE, server, server.getClientId());
Set<Scope> scopeset = new HashSet<>();
scopeset.add(manageScope);
scopeset.add(viewScope);
usersResource.updateScopes(scopeset);
}
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
if (managePermission == null) {
Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
Helper.addScopePermission(authz, server, MANAGE_PERMISSION_USERS, usersResource, manageScope, manageUsersPolicy);
}
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
if (viewPermission == null) {
Policy viewUsersPolicy = root.roles().viewUsersPolicy(server);
Helper.addScopePermission(authz, server, VIEW_PERMISSION_USERS, usersResource, viewScope, viewUsersPolicy);
}
}
@Override
public Map<String, String> getPermissions() {
Map<String, String> scopes = new HashMap<>();
scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission().getId());
scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission().getId());
return scopes;
}
@Override
public boolean isPermissionsEnabled() {
ResourceServer server = root.realmResourceServer();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return false;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
return policy != null;
}
@Override
public void setPermissionsEnabled(boolean enable) {
ClientModel client = root.getRealmManagementClient();
if (enable) {
initialize();
} else {
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) return;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
if (policy == null) {
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
}
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (usersResource == null) {
authz.getStoreFactory().getResourceStore().delete(usersResource.getId());
}
}
}
public boolean canManageDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_USERS);
}
@Override
public Resource resource() {
ResourceServer server = root.realmResourceServer();
if (server == null) return null;
return authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
}
@Override
public Policy managePermission() {
ResourceServer server = root.realmResourceServer();
return authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
}
@Override
public Policy viewPermission() {
ResourceServer server = root.realmResourceServer();
return authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
}
/**
* Is admin allowed to manage all users? In Authz terms, does the admin have the "manage" scope for the Users Authz resource?
*
* This method will follow the old default behavior (does the admin have the manage-users role) if any of these conditions
* are met.:
* - The admin is from the master realm managing a different realm
* - If the Authz objects are not set up correctly for the Users resource in Authz
* - The "manage" permission for the Users resource has an empty associatedPolicy list.
*
* Otherwise, it will use the Authz policy engine to resolve this answer.
*
* @return
*/
@Override
public boolean canManage() {
if (!root.isAdminSameRealm()) {
return canManageDefault();
}
ResourceServer server = root.realmResourceServer();
if (server == null) return canManageDefault();
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return canManageDefault();
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
if (policy == null) {
return canManageDefault();
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canManageDefault();
}
Scope scope = root.realmManageScope();
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireManage() {
if (!canManage()) {
throw new ForbiddenException();
}
}
/**
* Does current admin have manage permissions for this particular user?
*
* @param user
* @return
*/
@Override
public boolean canManage(UserModel user) {
return canManage() || canManageByGroup(user);
}
@Override
public void requireManage(UserModel user) {
if (!canManage(user)) {
throw new ForbiddenException();
}
}
private interface EvaluateGroup {
boolean evaluate(GroupModel group);
}
private boolean evaluateGroups(UserModel user, EvaluateGroup eval) {
for (GroupModel group : user.getGroups()) {
if (eval.evaluate(group)) return true;
}
return false;
}
private boolean evaluateHierarchy(UserModel user, EvaluateGroup eval) {
Set<GroupModel> visited = new HashSet<>();
for (GroupModel group : user.getGroups()) {
if (evaluateHierarchy(eval, group, visited)) return true;
}
return false;
}
private boolean evaluateHierarchy(EvaluateGroup eval, GroupModel group, Set<GroupModel> visited) {
if (visited.contains(group)) return false;
if (eval.evaluate(group)) {
return true;
}
visited.add(group);
if (group.getParent() == null) return false;
return evaluateHierarchy(eval, group.getParent(), visited);
}
private boolean canManageByGroup(UserModel user) {
/* no inheritance
return evaluateGroups(user,
(group) -> root.groups().canViewMembers(group)
);
*/
/* inheritance
*/
return evaluateHierarchy(user, (group) -> root.groups().canManageMembers(group));
}
private boolean canViewByGroup(UserModel user) {
/* no inheritance
return evaluateGroups(user,
(group) -> root.groups().canViewMembers(group)
);
*/
/* inheritance
*/
return evaluateHierarchy(user, (group) -> root.groups().canViewMembers(group));
}
public boolean canViewDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_USERS, AdminRoles.VIEW_USERS);
}
@Override
public boolean canQuery() {
return canViewDefault();
}
@Override
public void requireQuery() {
if (!canQuery()) {
throw new ForbiddenException();
}
}
/**
* Is admin allowed to view all users? In Authz terms, does the admin have the "view" scope for the Users Authz resource?
*
* This method will follow the old default behavior (does the admin have the view-users role) if any of these conditions
* are met.:
* - The admin is from the master realm managing a different realm
* - If the Authz objects are not set up correctly for the Users resource in Authz
* - The "view" permission for the Users resource has an empty associatedPolicy list.
*
* Otherwise, it will use the Authz policy engine to resolve this answer.
*
* @return
*/
@Override
public boolean canView() {
if (!root.isAdminSameRealm()) {
return canViewDefault();
}
ResourceServer server = root.realmResourceServer();
if (server == null) return canViewDefault();
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return canViewDefault();
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
if (policy == null) {
return canViewDefault();
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canViewDefault();
}
Scope scope = root.realmViewScope();
return root.evaluatePermission(resource, scope, server);
}
/**
* Does current admin have view permissions for this particular user?
*
* Evaluates in this order. If any true, return true:
* - canViewUsers
* - canManageUsers
*
*
* @param user
* @return
*/
@Override
public boolean canView(UserModel user) {
return canView() || canManage() || canViewByGroup(user) || canManageByGroup(user);
}
@Override
public void requireView(UserModel user) {
if (!canView(user)) {
throw new ForbiddenException();
}
}
@Override
public void requireView() {
if (!(canView() || canManage())) {
throw new ForbiddenException();
}
}
@Override
public boolean canImpersonate(UserModel user) {
return root.hasOneAdminRole(ImpersonationConstants.IMPERSONATION_ROLE);
}
@Override
public void requireImpersonate(UserModel user) {
if (!canImpersonate(user)) {
throw new ForbiddenException();
}
}
}

View file

@ -19,8 +19,9 @@ package org.keycloak.testsuite.admin;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.authorization.admin.permissions.MgmtPermissions; import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
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.models.AdminRoles; import org.keycloak.models.AdminRoles;
@ -35,24 +36,14 @@ import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.authorization.DecisionEffect;
import org.keycloak.representations.idm.authorization.DecisionStrategy; import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
import org.keycloak.representations.idm.authorization.PolicyEvaluationResponse;
import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.util.AdminClientUtil; import org.keycloak.testsuite.util.AdminClientUtil;
import javax.ws.rs.ClientErrorException; import javax.ws.rs.ClientErrorException;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.core.Response;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
/** /**
@ -73,7 +64,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
public static void setupPolices(KeycloakSession session) { public static void setupPolices(KeycloakSession session) {
RealmModel realm = session.realms().getRealmByName(TEST); RealmModel realm = session.realms().getRealmByName(TEST);
MgmtPermissions permissions = new MgmtPermissions(session, realm); AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
RoleModel realmRole = realm.addRole("realm-role"); RoleModel realmRole = realm.addRole("realm-role");
RoleModel realmRole2 = realm.addRole("realm-role2"); RoleModel realmRole2 = realm.addRole("realm-role2");
ClientModel client1 = realm.addClient("role-namespace"); ClientModel client1 = realm.addClient("role-namespace");
@ -110,7 +101,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
// setup Users manage policies // setup Users manage policies
{ {
permissions.users().setPermissionsEnabled(true); permissions.users().setPermissionsEnabled(true);
ResourceServer server = permissions.users().resourceServer(); ResourceServer server = permissions.realmResourceServer();
Policy managerPolicy = permissions.roles().rolePolicy(server, managerRole); Policy managerPolicy = permissions.roles().rolePolicy(server, managerRole);
Policy permission = permissions.users().managePermission(); Policy permission = permissions.users().managePermission();
permission.addAssociatedPolicy(managerPolicy); permission.addAssociatedPolicy(managerPolicy);
@ -177,9 +168,8 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
// test authorized // test authorized
{ {
UserModel user = session.users().getUserByUsername("authorized", realm); UserModel user = session.users().getUserByUsername("authorized", realm);
MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
permissionsForAdmin.setIdentity(user); Assert.assertTrue(permissionsForAdmin.users().canManage());
Assert.assertTrue(permissionsForAdmin.users().canManage(user));
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
@ -187,9 +177,8 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
// test composite role // test composite role
{ {
UserModel user = session.users().getUserByUsername("authorizedComposite", realm); UserModel user = session.users().getUserByUsername("authorizedComposite", realm);
MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
permissionsForAdmin.setIdentity(user); Assert.assertTrue(permissionsForAdmin.users().canManage());
Assert.assertTrue(permissionsForAdmin.users().canManage(user));
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
@ -198,9 +187,8 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
// test unauthorized // test unauthorized
{ {
UserModel user = session.users().getUserByUsername("unauthorized", realm); UserModel user = session.users().getUserByUsername("unauthorized", realm);
MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
permissionsForAdmin.setIdentity(user); Assert.assertFalse(permissionsForAdmin.users().canManage());
Assert.assertFalse(permissionsForAdmin.users().canManage(user));
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole)); Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole));
@ -210,9 +198,8 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
// test unauthorized mapper // test unauthorized mapper
{ {
UserModel user = session.users().getUserByUsername("unauthorizedMapper", realm); UserModel user = session.users().getUserByUsername("unauthorizedMapper", realm);
MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
permissionsForAdmin.setIdentity(user); Assert.assertTrue(permissionsForAdmin.users().canManage());
Assert.assertTrue(permissionsForAdmin.users().canManage(user));
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole)); Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole));
// will result to true because realmRole2 does not have any policies attached to this permission // will result to true because realmRole2 does not have any policies attached to this permission
@ -391,6 +378,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
} }
// testRestEvaluationMasterRealm // testRestEvaluationMasterRealm
// testRestEvaluationMasterAdminTestRealm // testRestEvaluationMasterAdminTestRealm
// test role deletion that it cleans up authz objects
} }

View file

@ -51,7 +51,7 @@ 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.ResourceServerRepresentation; import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation; import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.resources.admin.RealmAuth.Resource; import org.keycloak.services.resources.admin.AdminAuth.Resource;
import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher; import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
@ -77,8 +77,8 @@ import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.keycloak.services.resources.admin.RealmAuth.Resource.AUTHORIZATION; import static org.keycloak.services.resources.admin.AdminAuth.Resource.AUTHORIZATION;
import static org.keycloak.services.resources.admin.RealmAuth.Resource.CLIENT; import static org.keycloak.services.resources.admin.AdminAuth.Resource.CLIENT;
import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.ProfileAssume;
/** /**
@ -313,11 +313,18 @@ public class PermissionsTest extends AbstractKeycloakTest {
realm.removeDefaultGroup("nosuch"); realm.removeDefaultGroup("nosuch");
} }
}, Resource.REALM, true); }, Resource.REALM, true);
GroupRepresentation newGroup = new GroupRepresentation();
newGroup.setName("sample");
adminClient.realm(REALM_NAME).groups().add(newGroup);
GroupRepresentation group = adminClient.realms().realm(REALM_NAME).getGroupByPath("sample");
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.getGroupByPath("nosuch"); realm.getGroupByPath("sample");
} }
}, Resource.REALM, false); }, Resource.USER, false);
adminClient.realms().realm(REALM_NAME).groups().group(group.getId()).remove();
invoke(new InvocationWithResponse() { invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) { public void invoke(RealmResource realm, AtomicReference<Response> response) {
@ -954,6 +961,10 @@ public class PermissionsTest extends AbstractKeycloakTest {
@Test @Test
public void roles() { public void roles() {
RoleRepresentation newRole = new RoleRepresentation();
newRole.setName("sample-role");
adminClient.realm(REALM_NAME).roles().create(newRole);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().list(); realm.roles().list();
@ -961,12 +972,12 @@ public class PermissionsTest extends AbstractKeycloakTest {
}, Resource.REALM, false, true); }, Resource.REALM, false, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().get("nosuch").toRepresentation(); realm.roles().get("sample-role").toRepresentation();
} }
}, Resource.REALM, false); }, Resource.REALM, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().get("nosuch").update(new RoleRepresentation()); realm.roles().get("sample-role").update(newRole);
} }
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
@ -976,39 +987,42 @@ public class PermissionsTest extends AbstractKeycloakTest {
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().deleteRole("nosuch"); realm.roles().deleteRole("sample-role");
// need to recreate for other tests
realm.roles().create(newRole);
} }
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().get("nosuch").getRoleComposites(); realm.roles().get("sample-role").getRoleComposites();
} }
}, Resource.REALM, false); }, Resource.REALM, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().get("nosuch").addComposites(Collections.<RoleRepresentation>emptyList()); realm.roles().get("sample-role").addComposites(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().get("nosuch").deleteComposites(Collections.<RoleRepresentation>emptyList()); realm.roles().get("sample-role").deleteComposites(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().get("nosuch").getRoleComposites(); realm.roles().get("sample-role").getRoleComposites();
} }
}, Resource.REALM, false); }, Resource.REALM, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().get("nosuch").getRealmRoleComposites(); realm.roles().get("sample-role").getRealmRoleComposites();
} }
}, Resource.REALM, false); }, Resource.REALM, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.roles().get("nosuch").getClientRoleComposites("nosuch"); realm.roles().get("sample-role").getClientRoleComposites("nosuch");
} }
}, Resource.REALM, false); }, Resource.REALM, false);
adminClient.realms().realm(REALM_NAME).roles().deleteRole("sample-role");
} }
@Test @Test
@ -1175,51 +1189,61 @@ public class PermissionsTest extends AbstractKeycloakTest {
@Test @Test
public void rolesById() { public void rolesById() {
RoleRepresentation newRole = new RoleRepresentation();
newRole.setName("role-by-id");
adminClient.realm(REALM_NAME).roles().create(newRole);
RoleRepresentation role = adminClient.realm(REALM_NAME).roles().get("role-by-id").toRepresentation();
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().getRole("nosuch"); realm.rolesById().getRole(role.getId());
} }
}, Resource.REALM, false, true); }, Resource.REALM, false, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().updateRole("nosuch", new RoleRepresentation()); realm.rolesById().updateRole(role.getId(), role);
} }
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().deleteRole("nosuch"); realm.rolesById().deleteRole(role.getId());
// need to recreate for other tests
realm.roles().create(newRole);
RoleRepresentation temp = realm.roles().get("role-by-id").toRepresentation();
role.setId(temp.getId());
} }
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().getRoleComposites("nosuch"); realm.rolesById().getRoleComposites(role.getId());
} }
}, Resource.REALM, false, true); }, Resource.REALM, false, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().addComposites("nosuch", Collections.<RoleRepresentation>emptyList()); realm.rolesById().addComposites(role.getId(), Collections.<RoleRepresentation>emptyList());
} }
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().deleteComposites("nosuch", Collections.<RoleRepresentation>emptyList()); realm.rolesById().deleteComposites(role.getId(), Collections.<RoleRepresentation>emptyList());
} }
}, Resource.REALM, true); }, Resource.REALM, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().getRoleComposites("nosuch"); realm.rolesById().getRoleComposites(role.getId());
} }
}, Resource.REALM, false, true); }, Resource.REALM, false, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().getRealmRoleComposites("nosuch"); realm.rolesById().getRealmRoleComposites(role.getId());
} }
}, Resource.REALM, false, true); }, Resource.REALM, false, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.rolesById().getClientRoleComposites("nosuch", "nosuch"); realm.rolesById().getClientRoleComposites(role.getId(), "nosuch");
} }
}, Resource.REALM, false, true); }, Resource.REALM, false, true);
adminClient.realm(REALM_NAME).roles().deleteRole("role-by-id");
} }
@Test @Test
@ -1237,85 +1261,95 @@ public class PermissionsTest extends AbstractKeycloakTest {
} }
}, Resource.USER, true); }, Resource.USER, true);
GroupRepresentation group = adminClient.realms().realm(REALM_NAME).getGroupByPath("mygroup");
ClientRepresentation realmAccessClient = adminClient.realms().realm(REALM_NAME).clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").toRepresentation(); realm.groups().group(group.getId()).toRepresentation();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").update(new GroupRepresentation()); realm.groups().group(group.getId()).update(group);
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").remove(); realm.groups().group(group.getId()).members(0, 100);
}
}, Resource.USER, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.groups().group("nosuch").members(0, 100);
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new InvocationWithResponse() { invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) { public void invoke(RealmResource realm, AtomicReference<Response> response) {
response.set(realm.groups().group("nosuch").subGroup(new GroupRepresentation())); GroupRepresentation subgroup = new GroupRepresentation();
subgroup.setName("sub");
response.set(realm.groups().group(group.getId()).subGroup(subgroup));
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().getAll(); realm.groups().group(group.getId()).roles().getAll();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().realmLevel().listAll(); realm.groups().group(group.getId()).roles().realmLevel().listAll();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().realmLevel().listEffective(); realm.groups().group(group.getId()).roles().realmLevel().listEffective();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().realmLevel().listAvailable(); realm.groups().group(group.getId()).roles().realmLevel().listAvailable();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().realmLevel().add(Collections.<RoleRepresentation>emptyList()); realm.groups().group(group.getId()).roles().realmLevel().add(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().realmLevel().remove(Collections.<RoleRepresentation>emptyList()); realm.groups().group(group.getId()).roles().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().clientLevel("nosuch").listAll(); realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).listAll();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().clientLevel("nosuch").listEffective(); realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).listEffective();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().clientLevel("nosuch").listAvailable(); realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).listAvailable();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().clientLevel("nosuch").add(Collections.<RoleRepresentation>emptyList()); realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).add(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.groups().group("nosuch").roles().clientLevel("nosuch").remove(Collections.<RoleRepresentation>emptyList()); realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).remove(Collections.<RoleRepresentation>emptyList());
}
}, Resource.USER, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.groups().group(group.getId()).remove();
group.setId(null);
realm.groups().add(group);
GroupRepresentation temp = realm.getGroupByPath("mygroup");
group.setId(temp.getId());
} }
}, Resource.USER, true); }, Resource.USER, true);
} }
@ -1323,26 +1357,30 @@ public class PermissionsTest extends AbstractKeycloakTest {
// Permissions for impersonation tested in ImpersonationTest // Permissions for impersonation tested in ImpersonationTest
@Test @Test
public void users() { public void users() {
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.users().get("nosuch").toRepresentation();
}
}, Resource.USER, false);
invoke(new InvocationWithResponse() { invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) { public void invoke(RealmResource realm, AtomicReference<Response> response) {
response.set(realm.users().create(UserBuilder.create().username("testuser").build())); response.set(realm.users().create(UserBuilder.create().username("testuser").build()));
} }
}, Resource.USER, true); }, Resource.USER, true);
UserRepresentation user = adminClient.realms().realm(REALM_NAME).users().search("testUser").get(0);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").update(UserBuilder.create().enabled(true).build()); realm.users().get(user.getId()).remove();
realm.users().create(user);
UserRepresentation temp = realm.users().search("testUser").get(0);
user.setId(temp.getId());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().search("foo", 0, 1); realm.users().get(user.getId()).toRepresentation();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.users().get(user.getId()).update(user);
}
}, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().count(); realm.users().count();
@ -1350,149 +1388,150 @@ public class PermissionsTest extends AbstractKeycloakTest {
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").getUserSessions(); realm.users().get(user.getId()).getUserSessions();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").getOfflineSessions("nosuch"); realm.users().get(user.getId()).getOfflineSessions("nosuch");
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").getFederatedIdentity(); realm.users().get(user.getId()).getFederatedIdentity();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new InvocationWithResponse() { invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) { public void invoke(RealmResource realm, AtomicReference<Response> response) {
response.set(realm.users() response.set(realm.users()
.get("nosuch") .get(user.getId())
.addFederatedIdentity("nosuch", .addFederatedIdentity("nosuch",
FederatedIdentityBuilder.create().identityProvider("nosuch").userId("nosuch").userName("nosuch").build())); FederatedIdentityBuilder.create().identityProvider("nosuch").userId("nosuch").userName("nosuch").build()));
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").removeFederatedIdentity("nosuch"); realm.users().get(user.getId()).removeFederatedIdentity("nosuch");
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").getConsents(); realm.users().get(user.getId()).getConsents();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").revokeConsent("testclient"); realm.users().get(user.getId()).revokeConsent("testclient");
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").logout(); realm.users().get(user.getId()).logout();
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").remove(); realm.users().get(user.getId()).resetPassword(CredentialBuilder.create().password("password").build());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").resetPassword(CredentialBuilder.create().password("password").build()); realm.users().get(user.getId()).removeTotp();
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").removeTotp(); realm.users().get(user.getId()).resetPasswordEmail();
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").resetPasswordEmail(); realm.users().get(user.getId()).executeActionsEmail(Collections.<String>emptyList());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").executeActionsEmail(Collections.<String>emptyList()); realm.users().get(user.getId()).sendVerifyEmail();
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").sendVerifyEmail(); realm.users().get(user.getId()).groups();
}
}, Resource.USER, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.users().get("nosuch").groups();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").leaveGroup("nosuch"); realm.users().get(user.getId()).leaveGroup("nosuch");
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").joinGroup("nosuch"); realm.users().get(user.getId()).joinGroup("nosuch");
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().getAll(); realm.users().get(user.getId()).roles().getAll();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().realmLevel().listAll(); realm.users().get(user.getId()).roles().realmLevel().listAll();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().realmLevel().listAvailable(); realm.users().get(user.getId()).roles().realmLevel().listAvailable();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().realmLevel().listEffective(); realm.users().get(user.getId()).roles().realmLevel().listEffective();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().realmLevel().add(Collections.<RoleRepresentation>emptyList()); realm.users().get(user.getId()).roles().realmLevel().add(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().realmLevel().remove(Collections.<RoleRepresentation>emptyList()); realm.users().get(user.getId()).roles().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.USER, true); }, Resource.USER, true);
ClientRepresentation realmAccessClient = adminClient.realms().realm(REALM_NAME).clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().clientLevel("nosuch").listAll(); realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).listAll();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().clientLevel("nosuch").listAvailable(); realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).listAvailable();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().clientLevel("nosuch").listEffective(); realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).listEffective();
} }
}, Resource.USER, false); }, Resource.USER, false);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().clientLevel("nosuch").add(Collections.<RoleRepresentation>emptyList()); realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).add(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() { invoke(new Invocation() {
public void invoke(RealmResource realm) { public void invoke(RealmResource realm) {
realm.users().get("nosuch").roles().clientLevel("nosuch").remove(Collections.<RoleRepresentation>emptyList()); realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).remove(Collections.<RoleRepresentation>emptyList());
} }
}, Resource.USER, true); }, Resource.USER, true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.users().search("foo", 0, 1);
}
}, Resource.USER, false);
} }
@Test @Test