auth changes
This commit is contained in:
parent
ab763e7c5b
commit
c3ea847b3e
64 changed files with 3150 additions and 1469 deletions
|
@ -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);
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -98,4 +98,7 @@ public class AdminAuth {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Resource {
|
||||||
|
CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION, AUTHORIZATION
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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())) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
|
@ -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();
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue