Merge pull request #4256 from patriot1burke/master
KEYCLOAK-3444 KEYCLOAK-528
This commit is contained in:
commit
d77824ff98
145 changed files with 8178 additions and 2295 deletions
|
@ -141,6 +141,7 @@ public class JsonWebToken implements Serializable {
|
|||
}
|
||||
|
||||
public boolean hasAudience(String audience) {
|
||||
if (this.audience == null) return false;
|
||||
for (String a : this.audience) {
|
||||
if (a.equals(audience)) {
|
||||
return true;
|
||||
|
|
|
@ -65,6 +65,7 @@ public class ClientRepresentation {
|
|||
private Boolean useTemplateScope;
|
||||
private Boolean useTemplateMappers;
|
||||
private ResourceServerRepresentation authorizationSettings;
|
||||
private Map<String, Boolean> access;
|
||||
|
||||
|
||||
public String getId() {
|
||||
|
@ -366,4 +367,12 @@ public class ClientRepresentation {
|
|||
public void setAuthorizationSettings(ResourceServerRepresentation authorizationSettings) {
|
||||
this.authorizationSettings = authorizationSettings;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getAccess() {
|
||||
return access;
|
||||
}
|
||||
|
||||
public void setAccess(Map<String, Boolean> access) {
|
||||
this.access = access;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ public class GroupRepresentation {
|
|||
protected List<String> realmRoles;
|
||||
protected Map<String, List<String>> clientRoles;
|
||||
protected List<GroupRepresentation> subGroups;
|
||||
private Map<String, Boolean> access;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -97,4 +98,12 @@ public class GroupRepresentation {
|
|||
public void setSubGroups(List<GroupRepresentation> subGroups) {
|
||||
this.subGroups = subGroups;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getAccess() {
|
||||
return access;
|
||||
}
|
||||
|
||||
public void setAccess(Map<String, Boolean> access) {
|
||||
this.access = access;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.representations.idm;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ManagementPermissionReference {
|
||||
private boolean enabled;
|
||||
private String resource;
|
||||
private Map<String, String> scopePermissions;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public Map<String, String> getScopePermissions() {
|
||||
return scopePermissions;
|
||||
}
|
||||
|
||||
public void setScopePermissions(Map<String, String> scopePermissions) {
|
||||
this.scopePermissions = scopePermissions;
|
||||
}
|
||||
}
|
|
@ -62,6 +62,7 @@ public class UserRepresentation {
|
|||
protected List<SocialLinkRepresentation> socialLinks;
|
||||
|
||||
protected List<String> groups;
|
||||
private Map<String, Boolean> access;
|
||||
|
||||
public String getSelf() {
|
||||
return self;
|
||||
|
@ -264,4 +265,12 @@ public class UserRepresentation {
|
|||
public void setDisableableCredentialTypes(Set<String> disableableCredentialTypes) {
|
||||
this.disableableCredentialTypes = disableableCredentialTypes;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getAccess() {
|
||||
return access;
|
||||
}
|
||||
|
||||
public void setAccess(Map<String, Boolean> access) {
|
||||
this.access = access;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,13 +234,16 @@ public class RSAVerifierTest {
|
|||
public void testTokenAuth() throws Exception {
|
||||
token = new AccessToken();
|
||||
token.subject("CN=Client")
|
||||
.issuer("domain")
|
||||
.issuer("http://localhost:8080/auth/realms/demo")
|
||||
.addAccess("service").addRole("admin").verifyCaller(true);
|
||||
token.setEmail("bill@jboss.org");
|
||||
|
||||
String encoded = new JWSBuilder()
|
||||
.jsonContent(token)
|
||||
.rsa256(idpPair.getPrivate());
|
||||
|
||||
System.out.println("token size: " + encoded.length());
|
||||
|
||||
AccessToken v = null;
|
||||
try {
|
||||
v = verifySkeletonKeyToken(encoded);
|
||||
|
|
|
@ -46,6 +46,10 @@ public interface ClientsResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<ClientRepresentation> findAll();
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<ClientRepresentation> findAll(@QueryParam("viewableOnly") boolean viewableOnly);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<ClientRepresentation> findByClientId(@QueryParam("clientId") String clientId);
|
||||
|
|
|
@ -59,12 +59,6 @@ public class ResourceServerEntity {
|
|||
@Column(name = "POLICY_ENFORCE_MODE")
|
||||
private PolicyEnforcementMode policyEnforcementMode = PolicyEnforcementMode.ENFORCING;
|
||||
|
||||
@OneToMany(mappedBy = "resourceServer")
|
||||
private List<ResourceEntity> resources;
|
||||
|
||||
@OneToMany (mappedBy = "resourceServer")
|
||||
private List<ScopeEntity> scopes;
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
@ -97,22 +91,6 @@ public class ResourceServerEntity {
|
|||
this.policyEnforcementMode = policyEnforcementMode;
|
||||
}
|
||||
|
||||
public List<ResourceEntity> getResources() {
|
||||
return this.resources;
|
||||
}
|
||||
|
||||
public void setResources(final List<ResourceEntity> resources) {
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
public List<ScopeEntity> getScopes() {
|
||||
return this.scopes;
|
||||
}
|
||||
|
||||
public void setScopes(final List<ScopeEntity> scopes) {
|
||||
this.scopes = scopes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -19,9 +19,13 @@ package org.keycloak.authorization.jpa.store;
|
|||
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.jpa.entities.PolicyEntity;
|
||||
import org.keycloak.authorization.jpa.entities.ResourceEntity;
|
||||
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
|
||||
import org.keycloak.authorization.jpa.entities.ScopeEntity;
|
||||
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.ResourceServerStore;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
|
@ -65,24 +69,45 @@ public class JPAResourceServerStore implements ResourceServerStore {
|
|||
//entityManager.createNamedQuery("deletePolicyByResourceServer")
|
||||
// .setParameter("serverId", id).executeUpdate();
|
||||
|
||||
TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
|
||||
query.setParameter("serverId", id);
|
||||
List<String> result = query.getResultList();
|
||||
List<Policy> list = new LinkedList<>();
|
||||
for (String policyId : result) {
|
||||
entityManager.remove(entityManager.getReference(PolicyEntity.class, policyId));
|
||||
{
|
||||
TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
|
||||
query.setParameter("serverId", id);
|
||||
List<String> result = query.getResultList();
|
||||
for (String policyId : result) {
|
||||
entityManager.remove(entityManager.getReference(PolicyEntity.class, policyId));
|
||||
}
|
||||
}
|
||||
|
||||
entityManager.flush();
|
||||
entityManager.createNamedQuery("deleteResourceByResourceServer")
|
||||
.setParameter("serverId", id).executeUpdate();
|
||||
entityManager.flush();
|
||||
entityManager.createNamedQuery("deleteScopeByResourceServer")
|
||||
.setParameter("serverId", id).executeUpdate();
|
||||
entityManager.flush();
|
||||
//entityManager.createNamedQuery("deleteResourceByResourceServer")
|
||||
// .setParameter("serverId", id).executeUpdate();
|
||||
{
|
||||
TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByServerId", String.class);
|
||||
|
||||
query.setParameter("serverId", id);
|
||||
|
||||
List<String> result = query.getResultList();
|
||||
List<Resource> list = new LinkedList<>();
|
||||
for (String resourceId : result) {
|
||||
entityManager.remove(entityManager.getReference(ResourceEntity.class, resourceId));
|
||||
}
|
||||
}
|
||||
|
||||
//entityManager.createNamedQuery("deleteScopeByResourceServer")
|
||||
// .setParameter("serverId", id).executeUpdate();
|
||||
{
|
||||
TypedQuery<String> query = entityManager.createNamedQuery("findScopeIdByResourceServer", String.class);
|
||||
|
||||
query.setParameter("serverId", id);
|
||||
|
||||
List<String> result = query.getResultList();
|
||||
for (String scopeId : result) {
|
||||
entityManager.remove(entityManager.getReference(ScopeEntity.class, scopeId));
|
||||
}
|
||||
}
|
||||
|
||||
this.entityManager.remove(entity);
|
||||
entityManager.flush();
|
||||
entityManager.detach(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -360,6 +360,24 @@ public class JpaRealmProvider implements RealmProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
GroupModel.GroupRemovedEvent event = new GroupModel.GroupRemovedEvent() {
|
||||
@Override
|
||||
public RealmModel getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession getKeycloakSession() {
|
||||
return session;
|
||||
}
|
||||
};
|
||||
session.getKeycloakSessionFactory().publish(event);
|
||||
|
||||
session.users().preRemove(realm, group);
|
||||
|
||||
realm.removeDefaultGroup(group);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.policy.evaluation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class DecisionResult extends DecisionResultCollector {
|
||||
protected List<Result> results;
|
||||
protected Throwable error;
|
||||
|
||||
@Override
|
||||
protected void onComplete(List<Result> results) {
|
||||
this.results = results;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable cause) {
|
||||
this.error = cause;
|
||||
}
|
||||
|
||||
public boolean completed() {
|
||||
return results != null && error == null;
|
||||
}
|
||||
|
||||
public List<Result> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
|
@ -40,9 +40,9 @@ public class RealmSynchronizer implements Synchronizer<RealmRemovedEvent> {
|
|||
|
||||
if (resourceServer != null) {
|
||||
String id = resourceServer.getId();
|
||||
storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
|
||||
storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
|
||||
storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
|
||||
//storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
|
||||
//storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
|
||||
//storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
|
||||
storeFactory.getResourceServerStore().delete(id);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -14,18 +14,27 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.migration.migrators;
|
||||
|
||||
|
||||
import org.keycloak.migration.ModelVersion;
|
||||
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.migration.ModelVersion;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class MigrateTo3_2_0 implements Migration {
|
||||
|
||||
public static final ModelVersion VERSION = new ModelVersion("3.1.0");
|
||||
public static final ModelVersion VERSION = new ModelVersion("3.2.0");
|
||||
|
||||
@Override
|
||||
public void migrate(KeycloakSession session) {
|
||||
|
@ -34,6 +43,33 @@ public class MigrateTo3_2_0 implements Migration {
|
|||
if (!builder.contains(PasswordPolicy.HASH_ALGORITHM_ID) && "20000".equals(builder.get(PasswordPolicy.HASH_ITERATIONS_ID))) {
|
||||
realm.setPasswordPolicy(builder.remove(PasswordPolicy.HASH_ITERATIONS_ID).build(session));
|
||||
}
|
||||
|
||||
ClientModel realmAccess = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
if (realmAccess != null) {
|
||||
addRoles(realmAccess);
|
||||
}
|
||||
ClientModel masterAdminClient = realm.getMasterAdminClient();
|
||||
if (masterAdminClient != null) {
|
||||
addRoles(masterAdminClient);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void addRoles(ClientModel realmAccess) {
|
||||
RoleModel queryClients = realmAccess.addRole(AdminRoles.QUERY_CLIENTS);
|
||||
RoleModel queryUsers = realmAccess.addRole(AdminRoles.QUERY_USERS);
|
||||
RoleModel queryGroups = realmAccess.addRole(AdminRoles.QUERY_GROUPS);
|
||||
|
||||
RoleModel viewClients = realmAccess.getRole(AdminRoles.VIEW_CLIENTS);
|
||||
if (viewClients != null) {
|
||||
viewClients.addCompositeRole(queryClients);
|
||||
}
|
||||
RoleModel viewUsers = realmAccess.getRole(AdminRoles.VIEW_USERS);
|
||||
if (viewUsers != null) {
|
||||
viewUsers.addCompositeRole(queryUsers);
|
||||
viewUsers.addCompositeRole(queryGroups);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,5 +77,4 @@ public class MigrateTo3_2_0 implements Migration {
|
|||
public ModelVersion getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
package org.keycloak.models;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
|
@ -46,6 +49,21 @@ public class AdminRoles {
|
|||
public static String MANAGE_EVENTS = "manage-events";
|
||||
public static String MANAGE_AUTHORIZATION = "manage-authorization";
|
||||
|
||||
public static String[] ALL_REALM_ROLES = {CREATE_CLIENT, VIEW_REALM, VIEW_USERS, VIEW_CLIENTS, VIEW_EVENTS, VIEW_IDENTITY_PROVIDERS, VIEW_AUTHORIZATION, MANAGE_REALM, MANAGE_USERS, MANAGE_CLIENTS, MANAGE_EVENTS, MANAGE_IDENTITY_PROVIDERS, MANAGE_AUTHORIZATION};
|
||||
public static String QUERY_USERS = "query-users";
|
||||
public static String QUERY_CLIENTS = "query-clients";
|
||||
public static String QUERY_REALMS = "query-realms";
|
||||
public static String QUERY_GROUPS = "query-groups";
|
||||
|
||||
public static String[] ALL_REALM_ROLES = {CREATE_CLIENT, VIEW_REALM, VIEW_USERS, VIEW_CLIENTS, VIEW_EVENTS, VIEW_IDENTITY_PROVIDERS, VIEW_AUTHORIZATION, MANAGE_REALM, MANAGE_USERS, MANAGE_CLIENTS, MANAGE_EVENTS, MANAGE_IDENTITY_PROVIDERS, MANAGE_AUTHORIZATION, QUERY_USERS, QUERY_CLIENTS, QUERY_REALMS, QUERY_GROUPS};
|
||||
|
||||
public static Set<String> ALL_ROLES = new HashSet<>();
|
||||
static {
|
||||
for (String name : ALL_REALM_ROLES) {
|
||||
ALL_ROLES.add(name);
|
||||
}
|
||||
ALL_ROLES.add(ImpersonationConstants.IMPERSONATION_ROLE);
|
||||
ALL_ROLES.add(ADMIN);
|
||||
ALL_ROLES.add(CREATE_REALM);
|
||||
ALL_ROLES.add(CREATE_CLIENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,7 +168,6 @@ public class ModelToRepresentation {
|
|||
return rep;
|
||||
}
|
||||
|
||||
|
||||
public static UserRepresentation toRepresentation(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
UserRepresentation rep = new UserRepresentation();
|
||||
rep.setId(user.getId());
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.keycloak.models;
|
||||
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -26,6 +28,11 @@ import java.util.Set;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface GroupModel extends RoleMapperModel {
|
||||
interface GroupRemovedEvent extends ProviderEvent {
|
||||
RealmModel getRealm();
|
||||
GroupModel getGroup();
|
||||
KeycloakSession getKeycloakSession();
|
||||
}
|
||||
String getId();
|
||||
|
||||
String getName();
|
||||
|
|
|
@ -23,8 +23,8 @@ import org.keycloak.authorization.AuthorizationProvider;
|
|||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
|
||||
|
@ -33,22 +33,20 @@ import javax.ws.rs.Path;
|
|||
*/
|
||||
public class AuthorizationService {
|
||||
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
private final ClientModel client;
|
||||
private final KeycloakSession session;
|
||||
private final ResourceServer resourceServer;
|
||||
private final AuthorizationProvider authorization;
|
||||
private final AdminEventBuilder adminEvent;
|
||||
|
||||
public AuthorizationService(KeycloakSession session, ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public AuthorizationService(KeycloakSession session, ClientModel client, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.session = session;
|
||||
this.client = client;
|
||||
this.authorization = session.getProvider(AuthorizationProvider.class);
|
||||
this.adminEvent = adminEvent;
|
||||
this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().findByClient(this.client.getId());
|
||||
this.auth = auth;
|
||||
|
||||
if (auth != null) {
|
||||
this.auth.init(RealmAuth.Resource.AUTHORIZATION);
|
||||
}
|
||||
}
|
||||
|
||||
@Path("/resource-server")
|
||||
|
|
|
@ -22,15 +22,15 @@ import java.util.Map;
|
|||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class PermissionService extends PolicyService {
|
||||
|
||||
public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
super(resourceServer, authorization, auth, adminEvent);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
|||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.Urls;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -80,13 +80,13 @@ import org.keycloak.sessions.AuthenticationSessionModel;
|
|||
public class PolicyEvaluationService {
|
||||
|
||||
private final AuthorizationProvider authorization;
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
@Context
|
||||
private HttpRequest httpRequest;
|
||||
|
||||
private final ResourceServer resourceServer;
|
||||
|
||||
PolicyEvaluationService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
|
||||
PolicyEvaluationService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth) {
|
||||
this.resourceServer = resourceServer;
|
||||
this.authorization = authorization;
|
||||
this.auth = auth;
|
||||
|
@ -118,7 +118,7 @@ public class PolicyEvaluationService {
|
|||
@Consumes("application/json")
|
||||
@Produces("application/json")
|
||||
public Response evaluate(PolicyEvaluationRequest evaluationRequest) throws Throwable {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
CloseableKeycloakIdentity identity = createIdentity(evaluationRequest);
|
||||
try {
|
||||
return Response.ok(PolicyEvaluationResponseBuilder.build(evaluate(evaluationRequest, createEvaluationContext(evaluationRequest, identity)), resourceServer, authorization, identity)).build();
|
||||
|
|
|
@ -46,8 +46,8 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati
|
|||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
|
@ -58,10 +58,10 @@ public class PolicyResourceService {
|
|||
private final Policy policy;
|
||||
protected final ResourceServer resourceServer;
|
||||
protected final AuthorizationProvider authorization;
|
||||
protected final RealmAuth auth;
|
||||
protected final AdminPermissionEvaluator auth;
|
||||
private final AdminEventBuilder adminEvent;
|
||||
|
||||
public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.policy = policy;
|
||||
this.resourceServer = resourceServer;
|
||||
this.authorization = authorization;
|
||||
|
@ -73,8 +73,8 @@ public class PolicyResourceService {
|
|||
@Consumes("application/json")
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response update(@Context UriInfo uriInfo, String payload) {
|
||||
this.auth.requireManage();
|
||||
public Response update(@Context UriInfo uriInfo,String payload) {
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
|
||||
AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
|
||||
|
||||
|
@ -94,7 +94,7 @@ public class PolicyResourceService {
|
|||
|
||||
@DELETE
|
||||
public Response delete(@Context UriInfo uriInfo) {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
|
@ -119,7 +119,7 @@ public class PolicyResourceService {
|
|||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response findById() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
|
@ -137,7 +137,7 @@ public class PolicyResourceService {
|
|||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getDependentPolicies() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
|
@ -161,7 +161,7 @@ public class PolicyResourceService {
|
|||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getScopes() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
|
@ -182,7 +182,7 @@ public class PolicyResourceService {
|
|||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getResources() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
|
@ -203,7 +203,7 @@ public class PolicyResourceService {
|
|||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getAssociatedPolicies() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
|
|
|
@ -57,8 +57,8 @@ import org.keycloak.representations.idm.authorization.PolicyProviderRepresentati
|
|||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
|
@ -68,10 +68,10 @@ public class PolicyService {
|
|||
|
||||
protected final ResourceServer resourceServer;
|
||||
protected final AuthorizationProvider authorization;
|
||||
protected final RealmAuth auth;
|
||||
protected final AdminPermissionEvaluator auth;
|
||||
protected final AdminEventBuilder adminEvent;
|
||||
|
||||
public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.resourceServer = resourceServer;
|
||||
this.authorization = authorization;
|
||||
this.auth = auth;
|
||||
|
@ -103,8 +103,8 @@ public class PolicyService {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response create(@Context UriInfo uriInfo, String payload) {
|
||||
this.auth.requireManage();
|
||||
public Response create(@Context UriInfo uriInfo, String payload) {
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
|
||||
AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
|
||||
Policy policy = create(representation);
|
||||
|
@ -144,7 +144,7 @@ public class PolicyService {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response findByName(@QueryParam("name") String name) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
|
||||
if (name == null) {
|
||||
|
@ -171,7 +171,7 @@ public class PolicyService {
|
|||
@QueryParam("permission") Boolean permission,
|
||||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResult) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
|
||||
Map<String, String[]> search = new HashMap<>();
|
||||
|
||||
|
@ -250,7 +250,7 @@ public class PolicyService {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response findPolicyProviders() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
return Response.ok(
|
||||
authorization.getProviderFactories().stream()
|
||||
.map(provider -> {
|
||||
|
@ -268,7 +268,7 @@ public class PolicyService {
|
|||
|
||||
@Path("evaluate")
|
||||
public PolicyEvaluationService getPolicyEvaluateResource() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
PolicyEvaluationService resource = new PolicyEvaluationService(this.resourceServer, this.authorization, this.auth);
|
||||
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
|
|
|
@ -24,8 +24,8 @@ import org.keycloak.authorization.model.ResourceServer;
|
|||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,7 @@ import org.keycloak.util.JsonSerialization;
|
|||
*/
|
||||
public class PolicyTypeResourceService extends PolicyResourceService {
|
||||
|
||||
public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
super(policy, resourceServer, authorization, auth, adminEvent);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
|
|||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
|
@ -41,7 +41,7 @@ public class PolicyTypeService extends PolicyService {
|
|||
|
||||
private final String type;
|
||||
|
||||
PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
super(resourceServer, authorization, auth, adminEvent);
|
||||
this.type = type;
|
||||
}
|
||||
|
|
|
@ -56,8 +56,8 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
|||
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
|
@ -65,7 +65,7 @@ import org.keycloak.services.resources.admin.RealmAuth;
|
|||
public class ResourceServerService {
|
||||
|
||||
private final AuthorizationProvider authorization;
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
private final AdminEventBuilder adminEvent;
|
||||
private final KeycloakSession session;
|
||||
private ResourceServer resourceServer;
|
||||
|
@ -74,7 +74,7 @@ public class ResourceServerService {
|
|||
@Context
|
||||
private UriInfo uriInfo;
|
||||
|
||||
public ResourceServerService(AuthorizationProvider authorization, ResourceServer resourceServer, ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ResourceServerService(AuthorizationProvider authorization, ResourceServer resourceServer, ClientModel client, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.authorization = authorization;
|
||||
this.session = authorization.getKeycloakSession();
|
||||
this.client = client;
|
||||
|
@ -84,7 +84,7 @@ public class ResourceServerService {
|
|||
}
|
||||
|
||||
public void create(boolean newClient) {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
|
||||
UserModel serviceAccount = this.session.users().getServiceAccount(client);
|
||||
|
||||
|
@ -101,8 +101,8 @@ public class ResourceServerService {
|
|||
@PUT
|
||||
@Consumes("application/json")
|
||||
@Produces("application/json")
|
||||
public Response update(@Context UriInfo uriInfo, ResourceServerRepresentation server) {
|
||||
this.auth.requireManage();
|
||||
public Response update(ResourceServerRepresentation server) {
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
this.resourceServer.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement());
|
||||
this.resourceServer.setPolicyEnforcementMode(server.getPolicyEnforcementMode());
|
||||
audit(OperationType.UPDATE, uriInfo, false);
|
||||
|
@ -110,7 +110,7 @@ public class ResourceServerService {
|
|||
}
|
||||
|
||||
public void delete() {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
ResourceStore resourceStore = storeFactory.getResourceStore();
|
||||
String id = resourceServer.getId();
|
||||
|
@ -133,7 +133,7 @@ public class ResourceServerService {
|
|||
@GET
|
||||
@Produces("application/json")
|
||||
public Response findById() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
return Response.ok(toRepresentation(this.resourceServer, this.client)).build();
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ public class ResourceServerService {
|
|||
@GET
|
||||
@Produces("application/json")
|
||||
public Response exportSettings() {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
return Response.ok(ExportUtils.exportAuthorizationSettings(session, client)).build();
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ public class ResourceServerService {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response importSettings(@Context final UriInfo uriInfo, ResourceServerRepresentation rep) throws IOException {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
|
||||
rep.setClientId(client.getId());
|
||||
|
||||
|
@ -189,7 +189,7 @@ public class ResourceServerService {
|
|||
|
||||
@Path("/permission")
|
||||
public Object getPermissionTypeResource() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
PermissionService resource = new PermissionService(this.resourceServer, this.authorization, this.auth, adminEvent);
|
||||
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
|
|
|
@ -39,8 +39,8 @@ import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentatio
|
|||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
|
@ -74,11 +74,11 @@ import static org.keycloak.models.utils.RepresentationToModel.toModel;
|
|||
public class ResourceSetService {
|
||||
|
||||
private final AuthorizationProvider authorization;
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
private final AdminEventBuilder adminEvent;
|
||||
private ResourceServer resourceServer;
|
||||
|
||||
public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.resourceServer = resourceServer;
|
||||
this.authorization = authorization;
|
||||
this.auth = auth;
|
||||
|
@ -292,7 +292,7 @@ public class ResourceSetService {
|
|||
@NoCache
|
||||
@Produces("application/json")
|
||||
public Response find(@QueryParam("name") String name) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
|
||||
if (name == null) {
|
||||
|
@ -387,13 +387,13 @@ public class ResourceSetService {
|
|||
|
||||
private void requireView() {
|
||||
if (this.auth != null) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
}
|
||||
}
|
||||
|
||||
private void requireManage() {
|
||||
if (this.auth != null) {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
|||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.AdminEventBuilder;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
|
@ -65,11 +65,11 @@ import static org.keycloak.models.utils.RepresentationToModel.toModel;
|
|||
public class ScopeService {
|
||||
|
||||
private final AuthorizationProvider authorization;
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
private final AdminEventBuilder adminEvent;
|
||||
private ResourceServer resourceServer;
|
||||
|
||||
public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.resourceServer = resourceServer;
|
||||
this.authorization = authorization;
|
||||
this.auth = auth;
|
||||
|
@ -81,7 +81,7 @@ public class ScopeService {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response create(@Context UriInfo uriInfo, ScopeRepresentation scope) {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
Scope model = toModel(scope, this.resourceServer, authorization);
|
||||
|
||||
scope.setId(model.getId());
|
||||
|
@ -96,7 +96,7 @@ public class ScopeService {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response update(@Context UriInfo uriInfo, @PathParam("id") String id, ScopeRepresentation scope) {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
scope.setId(id);
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
Scope model = storeFactory.getScopeStore().findById(scope.getId(), resourceServer.getId());
|
||||
|
@ -115,7 +115,7 @@ public class ScopeService {
|
|||
@Path("{id}")
|
||||
@DELETE
|
||||
public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageAuthorization();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
List<Resource> resources = storeFactory.getResourceStore().findByScope(Arrays.asList(id), resourceServer.getId());
|
||||
|
||||
|
@ -154,7 +154,7 @@ public class ScopeService {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response findById(@PathParam("id") String id) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
Scope model = this.authorization.getStoreFactory().getScopeStore().findById(id, resourceServer.getId());
|
||||
|
||||
if (model == null) {
|
||||
|
@ -169,7 +169,7 @@ public class ScopeService {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getResources(@PathParam("id") String id) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
StoreFactory storeFactory = this.authorization.getStoreFactory();
|
||||
Scope model = storeFactory.getScopeStore().findById(id, resourceServer.getId());
|
||||
|
||||
|
@ -192,7 +192,7 @@ public class ScopeService {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getPermissions(@PathParam("id") String id) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
StoreFactory storeFactory = this.authorization.getStoreFactory();
|
||||
Scope model = storeFactory.getScopeStore().findById(id, resourceServer.getId());
|
||||
|
||||
|
@ -218,7 +218,7 @@ public class ScopeService {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response find(@QueryParam("name") String name) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
|
||||
if (name == null) {
|
||||
|
@ -241,7 +241,7 @@ public class ScopeService {
|
|||
@QueryParam("name") String name,
|
||||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResult) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewAuthorization();
|
||||
|
||||
Map<String, String[]> search = new HashMap<>();
|
||||
|
||||
|
|
|
@ -35,12 +35,19 @@ import java.util.Map;
|
|||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public abstract class AbstractEvaluationContext implements EvaluationContext {
|
||||
public class DefaultEvaluationContext implements EvaluationContext {
|
||||
|
||||
private final KeycloakSession keycloakSession;
|
||||
protected final KeycloakSession keycloakSession;
|
||||
protected final Identity identity;
|
||||
|
||||
public AbstractEvaluationContext(KeycloakSession keycloakSession) {
|
||||
public DefaultEvaluationContext(Identity identity, KeycloakSession keycloakSession) {
|
||||
this.keycloakSession = keycloakSession;
|
||||
this.identity = identity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identity getIdentity() {
|
||||
return identity;
|
||||
}
|
||||
|
||||
public Map<String, Collection<String>> getBaseAttributes() {
|
||||
|
@ -60,4 +67,9 @@ public abstract class AbstractEvaluationContext implements EvaluationContext {
|
|||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attributes getAttributes() {
|
||||
return Attributes.from(getBaseAttributes());
|
||||
}
|
||||
}
|
|
@ -18,34 +18,28 @@
|
|||
|
||||
package org.keycloak.authorization.common;
|
||||
|
||||
import org.keycloak.authorization.attribute.Attributes;
|
||||
import org.keycloak.authorization.identity.Identity;
|
||||
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class KeycloakEvaluationContext implements EvaluationContext {
|
||||
public class KeycloakEvaluationContext extends DefaultEvaluationContext {
|
||||
|
||||
private final KeycloakIdentity identity;
|
||||
private final KeycloakSession keycloakSession;
|
||||
|
||||
public KeycloakEvaluationContext(KeycloakSession keycloakSession) {
|
||||
this(new KeycloakIdentity(keycloakSession), keycloakSession);
|
||||
}
|
||||
|
||||
public KeycloakEvaluationContext(KeycloakIdentity identity, KeycloakSession keycloakSession) {
|
||||
super(identity, keycloakSession);
|
||||
this.identity = identity;
|
||||
this.keycloakSession = keycloakSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,27 +48,13 @@ public class KeycloakEvaluationContext implements EvaluationContext {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Attributes getAttributes() {
|
||||
HashMap<String, Collection<String>> attributes = new HashMap<>();
|
||||
|
||||
attributes.put("kc.time.date_time", Arrays.asList(new SimpleDateFormat("MM/dd/yyyy hh:mm:ss").format(new Date())));
|
||||
attributes.put("kc.client.network.ip_address", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteAddr()));
|
||||
attributes.put("kc.client.network.host", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteHost()));
|
||||
|
||||
public Map<String, Collection<String>> getBaseAttributes() {
|
||||
Map<String, Collection<String>> attributes = super.getBaseAttributes();
|
||||
AccessToken accessToken = this.identity.getAccessToken();
|
||||
|
||||
if (accessToken != null) {
|
||||
attributes.put("kc.client.id", Arrays.asList(accessToken.getIssuedFor()));
|
||||
}
|
||||
|
||||
List<String> userAgents = this.keycloakSession.getContext().getRequestHeaders().getRequestHeader("User-Agent");
|
||||
|
||||
if (userAgents != null) {
|
||||
attributes.put("kc.client.user_agent", userAgents);
|
||||
}
|
||||
|
||||
attributes.put("kc.realm.name", Arrays.asList(this.keycloakSession.getContext().getRealm().getName()));
|
||||
|
||||
return Attributes.from(attributes);
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,74 @@ public class KeycloakIdentity implements Identity {
|
|||
this(Tokens.getAccessToken(keycloakSession), keycloakSession);
|
||||
}
|
||||
|
||||
public KeycloakIdentity(KeycloakSession keycloakSession, AccessToken accessToken) {
|
||||
this(accessToken, keycloakSession, keycloakSession.getContext().getRealm());
|
||||
}
|
||||
|
||||
public KeycloakIdentity(AccessToken accessToken, KeycloakSession keycloakSession, RealmModel realm) {
|
||||
if (accessToken == null) {
|
||||
throw new ErrorResponseException("invalid_bearer_token", "Could not obtain bearer access_token from request.", Status.FORBIDDEN);
|
||||
}
|
||||
if (keycloakSession == null) {
|
||||
throw new ErrorResponseException("no_keycloak_session", "No keycloak session", Status.FORBIDDEN);
|
||||
}
|
||||
if (realm == null) {
|
||||
throw new ErrorResponseException("no_keycloak_session", "No realm set", Status.FORBIDDEN);
|
||||
}
|
||||
this.accessToken = accessToken;
|
||||
this.keycloakSession = keycloakSession;
|
||||
this.realm = realm;
|
||||
|
||||
Map<String, Collection<String>> attributes = new HashMap<>();
|
||||
|
||||
try {
|
||||
ObjectNode objectNode = JsonSerialization.createObjectNode(this.accessToken);
|
||||
Iterator<String> iterator = objectNode.fieldNames();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
String fieldName = iterator.next();
|
||||
JsonNode fieldValue = objectNode.get(fieldName);
|
||||
List<String> values = new ArrayList<>();
|
||||
|
||||
if (fieldValue.isArray()) {
|
||||
Iterator<JsonNode> valueIterator = fieldValue.iterator();
|
||||
|
||||
while (valueIterator.hasNext()) {
|
||||
values.add(valueIterator.next().asText());
|
||||
}
|
||||
} else {
|
||||
String value = fieldValue.asText();
|
||||
|
||||
if (StringUtil.isNullOrEmpty(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
if (!values.isEmpty()) {
|
||||
attributes.put(fieldName, values);
|
||||
}
|
||||
}
|
||||
|
||||
AccessToken.Access realmAccess = accessToken.getRealmAccess();
|
||||
|
||||
if (realmAccess != null) {
|
||||
attributes.put("kc.realm.roles", realmAccess.getRoles());
|
||||
}
|
||||
|
||||
Map<String, AccessToken.Access> resourceAccess = accessToken.getResourceAccess();
|
||||
|
||||
if (resourceAccess != null) {
|
||||
resourceAccess.forEach((clientId, access) -> attributes.put("kc.client." + clientId + ".roles", access.getRoles()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error while reading attributes from security token.", e);
|
||||
}
|
||||
|
||||
this.attributes = Attributes.from(attributes);
|
||||
}
|
||||
|
||||
public KeycloakIdentity(AccessToken accessToken, KeycloakSession keycloakSession) {
|
||||
if (accessToken == null) {
|
||||
throw new ErrorResponseException("invalid_bearer_token", "Could not obtain bearer access_token from request.", Status.FORBIDDEN);
|
||||
|
|
|
@ -34,7 +34,8 @@ public class UserModelIdentity implements Identity {
|
|||
protected RealmModel realm;
|
||||
protected UserModel user;
|
||||
|
||||
public UserModelIdentity(UserModel user) {
|
||||
public UserModelIdentity(RealmModel realm, UserModel user) {
|
||||
this.realm = realm;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
package org.keycloak.authorization.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -48,6 +50,10 @@ import org.keycloak.representations.idm.authorization.Permission;
|
|||
*/
|
||||
public final class Permissions {
|
||||
|
||||
public static List<ResourcePermission> permission(ResourceServer server, Resource resource, Scope scope) {
|
||||
return Arrays.asList(new ResourcePermission(resource, Arrays.asList(scope), server));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of permissions for all resources and scopes that belong to the given <code>resourceServer</code> and
|
||||
* <code>identity</code>.
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.provider.ProviderManager;
|
|||
import org.keycloak.provider.ProviderManagerDeployer;
|
||||
import org.keycloak.provider.ProviderManagerRegistry;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -93,6 +94,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
|
|||
}
|
||||
// make the session factory ready for hot deployment
|
||||
ProviderManagerRegistry.SINGLETON.setDeployer(this);
|
||||
AdminPermissions.registerListener(this);
|
||||
|
||||
}
|
||||
protected Map<Class<? extends Provider>, Map<String, ProviderFactory>> getFactoriesCopy() {
|
||||
|
|
|
@ -31,12 +31,15 @@ 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.protocol.oidc.utils.AuthorizeClientUtil;
|
||||
import org.keycloak.representations.JsonWebToken;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
|
||||
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyException;
|
||||
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.util.TokenUtil;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
@ -231,44 +234,72 @@ public class ClientRegistrationAuth {
|
|||
return initialAccessModel;
|
||||
}
|
||||
|
||||
private boolean hasRole(String... role) {
|
||||
private boolean hasRole(String... roles) {
|
||||
try {
|
||||
Map<String, Object> otherClaims = jwt.getOtherClaims();
|
||||
if (otherClaims != null) {
|
||||
Map<String, Map<String, List<String>>> resourceAccess = (Map<String, Map<String, List<String>>>) jwt.getOtherClaims().get("resource_access");
|
||||
if (resourceAccess == null) {
|
||||
return false;
|
||||
}
|
||||
if (jwt.getIssuedFor().equals(Constants.ADMIN_CLI_CLIENT_ID)
|
||||
|| jwt.getIssuedFor().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
|
||||
return hasRoleInModel(roles);
|
||||
|
||||
List<String> roles = null;
|
||||
|
||||
Map<String, List<String>> map;
|
||||
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||
map = resourceAccess.get(realm.getMasterAdminClient().getClientId());
|
||||
} else {
|
||||
map = resourceAccess.get(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
}
|
||||
|
||||
if (map != null) {
|
||||
roles = map.get("roles");
|
||||
}
|
||||
|
||||
if (roles == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String r : role) {
|
||||
if (roles.contains(r)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return hasRoleInToken(roles);
|
||||
}
|
||||
return false;
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasRoleInModel(String[] roles) {
|
||||
ClientModel roleNamespace;
|
||||
UserModel user = session.users().getUserById(jwt.getSubject(), realm);
|
||||
if (user == null) {
|
||||
return false;
|
||||
}
|
||||
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||
roleNamespace = realm.getMasterAdminClient();
|
||||
} else {
|
||||
roleNamespace = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
}
|
||||
for (String role : roles) {
|
||||
RoleModel roleModel = roleNamespace.getRole(role);
|
||||
if (user.hasRole(roleModel)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasRoleInToken(String[] role) {
|
||||
Map<String, Object> otherClaims = jwt.getOtherClaims();
|
||||
if (otherClaims != null) {
|
||||
Map<String, Map<String, List<String>>> resourceAccess = (Map<String, Map<String, List<String>>>) jwt.getOtherClaims().get("resource_access");
|
||||
if (resourceAccess == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> roles = null;
|
||||
|
||||
Map<String, List<String>> map;
|
||||
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||
map = resourceAccess.get(realm.getMasterAdminClient().getClientId());
|
||||
} else {
|
||||
map = resourceAccess.get(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
}
|
||||
|
||||
if (map != null) {
|
||||
roles = map.get("roles");
|
||||
}
|
||||
|
||||
if (roles == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String r : role) {
|
||||
if (roles.contains(r)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean authenticateClient(ClientModel client) {
|
||||
if (client == null) {
|
||||
return false;
|
||||
|
|
|
@ -159,7 +159,6 @@ public class RealmManager {
|
|||
ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
|
||||
adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
|
||||
}
|
||||
adminConsole.addScopeMapping(adminRole);
|
||||
}
|
||||
|
||||
protected void setupAdminConsoleLocaleMapper(RealmModel realm) {
|
||||
|
@ -194,10 +193,21 @@ public class RealmManager {
|
|||
ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
|
||||
adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
|
||||
}
|
||||
adminCli.addScopeMapping(adminRole);
|
||||
}
|
||||
|
||||
}
|
||||
public void addQueryCompositeRoles(ClientModel realmAccess) {
|
||||
RoleModel queryClients = realmAccess.getRole(AdminRoles.QUERY_CLIENTS);
|
||||
RoleModel queryUsers = realmAccess.getRole(AdminRoles.QUERY_USERS);
|
||||
RoleModel queryGroups = realmAccess.getRole(AdminRoles.QUERY_GROUPS);
|
||||
|
||||
RoleModel viewClients = realmAccess.getRole(AdminRoles.VIEW_CLIENTS);
|
||||
viewClients.addCompositeRole(queryClients);
|
||||
RoleModel viewUsers = realmAccess.getRole(AdminRoles.VIEW_USERS);
|
||||
viewUsers.addCompositeRole(queryUsers);
|
||||
viewUsers.addCompositeRole(queryGroups);
|
||||
}
|
||||
|
||||
|
||||
public String getRealmAdminClientId(RealmModel realm) {
|
||||
return Constants.REALM_MANAGEMENT_CLIENT_ID;
|
||||
|
@ -325,6 +335,7 @@ public class RealmManager {
|
|||
role.setScopeParamRequired(false);
|
||||
adminRole.addCompositeRole(role);
|
||||
}
|
||||
addQueryCompositeRoles(realmAdminApp);
|
||||
}
|
||||
|
||||
private void checkMasterAdminManagementRoles(RealmModel realm) {
|
||||
|
@ -338,6 +349,7 @@ public class RealmManager {
|
|||
addAndSetAdminRole(r, masterAdminClient, adminRole);
|
||||
}
|
||||
}
|
||||
addQueryCompositeRoles(masterAdminClient);
|
||||
}
|
||||
|
||||
|
||||
|
@ -360,6 +372,7 @@ public class RealmManager {
|
|||
for (String r : AdminRoles.ALL_REALM_ROLES) {
|
||||
addAndSetAdminRole(r, realmAdminClient, adminRole);
|
||||
}
|
||||
addQueryCompositeRoles(realmAdminClient);
|
||||
}
|
||||
|
||||
private void addAndSetAdminRole(String roleName, ClientModel parentClient, RoleModel parentRole) {
|
||||
|
@ -383,6 +396,7 @@ public class RealmManager {
|
|||
addAndSetAdminRole(r, realmAdminClient, adminRole);
|
||||
}
|
||||
}
|
||||
addQueryCompositeRoles(realmAdminClient);
|
||||
}
|
||||
|
||||
|
||||
|
@ -500,7 +514,8 @@ public class RealmManager {
|
|||
// I need to postpone impersonation because it needs "realm-management" client and its roles set
|
||||
if (postponeImpersonationSetup) {
|
||||
setupImpersonationService(realm);
|
||||
}
|
||||
String realmAdminClientId = getRealmAdminClientId(realm);
|
||||
}
|
||||
|
||||
if (postponeAdminCliSetup) {
|
||||
setupAdminCli(realm);
|
||||
|
|
|
@ -98,4 +98,7 @@ public class AdminAuth {
|
|||
return false;
|
||||
}
|
||||
|
||||
public enum Resource {
|
||||
CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION, AUTHORIZATION
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ import org.keycloak.services.managers.AuthenticationManager;
|
|||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.Cors;
|
||||
import org.keycloak.services.resources.admin.info.ServerInfoAdminResource;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.services.resources.admin.permissions.RealmsPermissionEvaluator;
|
||||
import org.keycloak.theme.Theme;
|
||||
import org.keycloak.theme.ThemeProvider;
|
||||
|
||||
|
@ -229,7 +231,7 @@ public class AdminRoot {
|
|||
handlePreflightRequest();
|
||||
|
||||
AdminAuth auth = authenticateRealmAdminRequest(headers);
|
||||
if (!isAdmin(auth)) {
|
||||
if (!AdminPermissions.realms(session, auth).isAdmin()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
|
@ -244,26 +246,6 @@ public class AdminRoot {
|
|||
return adminResource;
|
||||
}
|
||||
|
||||
protected boolean isAdmin(AdminAuth auth) {
|
||||
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||
if (auth.hasOneOfRealmRole(AdminRoles.ADMIN, AdminRoles.CREATE_REALM)) {
|
||||
return true;
|
||||
}
|
||||
for (RealmModel realm : session.realms().getRealms()) {
|
||||
ClientModel client = realm.getMasterAdminClient();
|
||||
if (auth.hasOneOfAppRole(client, AdminRoles.ALL_REALM_ROLES)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
ClientModel client = auth.getRealm().getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm()));
|
||||
return auth.hasOneOfAppRole(client, AdminRoles.ALL_REALM_ROLES);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handlePreflightRequest() {
|
||||
if (request.getHttpMethod().equalsIgnoreCase("OPTIONS")) {
|
||||
logger.debug("Cors admin pre-flight");
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.keycloak.services.resources.admin;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
|
@ -26,6 +27,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserLoginFailureModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.BruteForceProtector;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
|
@ -48,7 +50,7 @@ import java.util.Map;
|
|||
*/
|
||||
public class AttackDetectionResource {
|
||||
protected static final Logger logger = Logger.getLogger(AttackDetectionResource.class);
|
||||
protected RealmAuth auth;
|
||||
protected AdminPermissionEvaluator auth;
|
||||
protected RealmModel realm;
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
||||
|
@ -64,12 +66,10 @@ public class AttackDetectionResource {
|
|||
@Context
|
||||
protected HttpHeaders headers;
|
||||
|
||||
public AttackDetectionResource(RealmAuth auth, RealmModel realm, AdminEventBuilder adminEvent) {
|
||||
public AttackDetectionResource(AdminPermissionEvaluator auth, RealmModel realm, AdminEventBuilder adminEvent) {
|
||||
this.auth = auth;
|
||||
this.realm = realm;
|
||||
this.adminEvent = adminEvent.realm(realm).resource(ResourceType.USER_LOGIN_FAILURE);
|
||||
|
||||
auth.init(RealmAuth.Resource.USER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,7 +83,12 @@ public class AttackDetectionResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Map<String, Object> bruteForceUserStatus(@PathParam("userId") String userId) {
|
||||
auth.requireView();
|
||||
UserModel user = session.users().getUserById(userId, realm);
|
||||
if (user == null) {
|
||||
auth.users().requireView();
|
||||
} else {
|
||||
auth.users().requireView(user);
|
||||
}
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("disabled", false);
|
||||
|
@ -92,7 +97,6 @@ public class AttackDetectionResource {
|
|||
data.put("lastIPFailure", "n/a");
|
||||
if (!realm.isBruteForceProtected()) return data;
|
||||
|
||||
UserModel user = session.users().getUserById(userId, realm);
|
||||
|
||||
UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId);
|
||||
if (model == null) return data;
|
||||
|
@ -115,8 +119,12 @@ public class AttackDetectionResource {
|
|||
@Path("brute-force/users/{userId}")
|
||||
@DELETE
|
||||
public void clearBruteForceForUser(@PathParam("userId") String userId) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(userId, realm);
|
||||
if (user == null) {
|
||||
auth.users().requireManage();
|
||||
} else {
|
||||
auth.users().requireManage(user);
|
||||
}
|
||||
UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId);
|
||||
if (model != null) {
|
||||
session.sessions().removeUserLoginFailure(realm, userId);
|
||||
|
@ -133,7 +141,7 @@ public class AttackDetectionResource {
|
|||
@Path("brute-force/users")
|
||||
@DELETE
|
||||
public void clearAllBruteForce() {
|
||||
auth.requireManage();
|
||||
auth.users().requireManage();
|
||||
|
||||
session.sessions().removeAllUserLoginFailures(realm);
|
||||
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.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.utils.CredentialHelper;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -80,18 +81,17 @@ public class AuthenticationManagementResource {
|
|||
|
||||
private final RealmModel realm;
|
||||
private final KeycloakSession session;
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
private AdminEventBuilder adminEvent;
|
||||
@Context
|
||||
private UriInfo uriInfo;
|
||||
|
||||
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.session = session;
|
||||
this.auth = auth;
|
||||
this.auth.init(RealmAuth.Resource.REALM);
|
||||
this.adminEvent = adminEvent.resource(ResourceType.AUTH_FLOW);
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Map<String, Object>> getFormProviders() {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAuthenticator.class);
|
||||
return buildProviderMetadata(factories);
|
||||
|
@ -121,7 +121,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Map<String, Object>> getAuthenticatorProviders() {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(Authenticator.class);
|
||||
return buildProviderMetadata(factories);
|
||||
|
@ -137,7 +137,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Map<String, Object>> getClientAuthenticatorProviders() {
|
||||
auth.requireAny();
|
||||
auth.requireAnyAdminRole();
|
||||
|
||||
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);
|
||||
return buildProviderMetadata(factories);
|
||||
|
@ -167,7 +167,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Map<String, Object>> getFormActionProviders() {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAction.class);
|
||||
return buildProviderMetadata(factories);
|
||||
|
@ -184,7 +184,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<AuthenticationFlowRepresentation> getFlows() {
|
||||
auth.requireAny();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
List<AuthenticationFlowRepresentation> flows = new LinkedList<>();
|
||||
for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
|
||||
|
@ -207,7 +207,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response createFlow(AuthenticationFlowRepresentation flow) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
if (flow.getAlias() == null || flow.getAlias().isEmpty()) {
|
||||
return ErrorResponse.exists("Failed to create flow with empty alias name");
|
||||
|
@ -235,7 +235,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public AuthenticationFlowRepresentation getFlow(@PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
AuthenticationFlowModel flow = realm.getAuthenticationFlowById(id);
|
||||
if (flow == null) {
|
||||
|
@ -253,7 +253,7 @@ public class AuthenticationManagementResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public void deleteFlow(@PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
deleteFlow(id, true);
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response copy(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
String newName = data.get("newName");
|
||||
if (realm.getFlowByAlias(newName) != null) {
|
||||
|
@ -351,7 +351,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response addExecutionFlow(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias);
|
||||
if (parentFlow == null) {
|
||||
|
@ -403,7 +403,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void addExecution(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias);
|
||||
if (parentFlow == null) {
|
||||
|
@ -450,7 +450,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getExecutions(@PathParam("flowAlias") String flowAlias) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias);
|
||||
if (flow == null) {
|
||||
|
@ -535,7 +535,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void updateExecutions(@PathParam("flowAlias") String flowAlias, AuthenticationExecutionInfoRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias);
|
||||
if (flow == null) {
|
||||
|
@ -566,7 +566,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response addExecution(AuthenticationExecutionRepresentation execution) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticationExecutionModel model = RepresentationToModel.toModel(realm, execution);
|
||||
AuthenticationFlowModel parentFlow = getParentFlow(model);
|
||||
|
@ -601,7 +601,7 @@ public class AuthenticationManagementResource {
|
|||
@POST
|
||||
@NoCache
|
||||
public void raisePriority(@PathParam("executionId") String execution) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
|
||||
if (model == null) {
|
||||
|
@ -647,7 +647,7 @@ public class AuthenticationManagementResource {
|
|||
@POST
|
||||
@NoCache
|
||||
public void lowerPriority(@PathParam("executionId") String execution) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
|
||||
if (model == null) {
|
||||
|
@ -687,7 +687,7 @@ public class AuthenticationManagementResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public void removeExecution(@PathParam("executionId") String execution) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
|
||||
if (model == null) {
|
||||
|
@ -723,7 +723,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response newExecutionConfig(@PathParam("executionId") String execution, AuthenticatorConfigRepresentation json) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
|
||||
if (model == null) {
|
||||
|
@ -753,7 +753,7 @@ public class AuthenticationManagementResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("executionId") String execution,@PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
|
||||
if (config == null) {
|
||||
|
@ -773,7 +773,7 @@ public class AuthenticationManagementResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<Map<String, String>> getUnregisteredRequiredActions() {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class);
|
||||
List<Map<String, String>> unregisteredList = new LinkedList<>();
|
||||
|
@ -807,7 +807,7 @@ public class AuthenticationManagementResource {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public void registerRequiredAction(Map<String, String> data) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
String providerId = data.get("providerId");
|
||||
String name = data.get("name");
|
||||
|
@ -834,7 +834,7 @@ public class AuthenticationManagementResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RequiredActionProviderRepresentation> getRequiredActions() {
|
||||
auth.requireAny();
|
||||
auth.requireAnyAdminRole();
|
||||
|
||||
List<RequiredActionProviderRepresentation> list = new LinkedList<>();
|
||||
for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) {
|
||||
|
@ -863,7 +863,7 @@ public class AuthenticationManagementResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public RequiredActionProviderRepresentation getRequiredAction(@PathParam("alias") String alias) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
|
||||
if (model == null) {
|
||||
|
@ -883,7 +883,7 @@ public class AuthenticationManagementResource {
|
|||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void updateRequiredAction(@PathParam("alias") String alias, RequiredActionProviderRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
|
||||
if (model == null) {
|
||||
|
@ -909,7 +909,7 @@ public class AuthenticationManagementResource {
|
|||
@Path("required-actions/{alias}")
|
||||
@DELETE
|
||||
public void removeRequiredAction(@PathParam("alias") String alias) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
|
||||
if (model == null) {
|
||||
|
@ -928,7 +928,7 @@ public class AuthenticationManagementResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public AuthenticatorConfigInfoRepresentation getAuthenticatorConfigDescription(@PathParam("providerId") String providerId) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
ConfigurableAuthenticatorFactory factory = CredentialHelper.getConfigurableAuthenticatorFactory(session, providerId);
|
||||
if (factory == null) {
|
||||
|
@ -959,7 +959,7 @@ public class AuthenticationManagementResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Map<String, List<ConfigPropertyRepresentation>> getPerClientConfigDescription() {
|
||||
auth.requireAny();
|
||||
auth.requireAnyAdminRole();
|
||||
|
||||
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);
|
||||
|
||||
|
@ -991,7 +991,7 @@ public class AuthenticationManagementResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response createAuthenticatorConfig(AuthenticatorConfigRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticatorConfigModel config = realm.addAuthenticatorConfig(RepresentationToModel.toModel(rep));
|
||||
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)
|
||||
@NoCache
|
||||
public AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
|
||||
if (config == null) {
|
||||
|
@ -1025,7 +1025,7 @@ public class AuthenticationManagementResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public void removeAuthenticatorConfig(@PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
|
||||
if (config == null) {
|
||||
|
@ -1057,7 +1057,7 @@ public class AuthenticationManagementResource {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public void updateAuthenticatorConfig(@PathParam("id") String id, AuthenticatorConfigRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AuthenticatorConfigModel exists = realm.getAuthenticatorConfigById(id);
|
||||
if (exists == null) {
|
||||
|
|
|
@ -37,10 +37,12 @@ import org.keycloak.models.utils.KeycloakModelUtils;
|
|||
import org.keycloak.representations.KeyStoreConfig;
|
||||
import org.keycloak.representations.idm.CertificateRepresentation;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.util.CertificateInfoHelper;
|
||||
import org.keycloak.util.JWKSUtils;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
|
@ -73,13 +75,13 @@ public class ClientAttributeCertificateResource {
|
|||
public static final String JSON_WEB_KEY_SET = "JSON Web Key Set";
|
||||
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
protected ClientModel client;
|
||||
protected KeycloakSession session;
|
||||
protected AdminEventBuilder adminEvent;
|
||||
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.auth = auth;
|
||||
this.client = client;
|
||||
|
@ -97,11 +99,7 @@ public class ClientAttributeCertificateResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public CertificateRepresentation getKeyInfo() {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
CertificateRepresentation info = CertificateInfoHelper.getCertificateFromClient(client, attributePrefix);
|
||||
return info;
|
||||
|
@ -117,11 +115,7 @@ public class ClientAttributeCertificateResource {
|
|||
@Path("generate")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public CertificateRepresentation generate() {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
CertificateRepresentation info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId());
|
||||
|
||||
|
@ -145,11 +139,7 @@ public class ClientAttributeCertificateResource {
|
|||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public CertificateRepresentation uploadJks(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
try {
|
||||
CertificateRepresentation info = getCertFromRequest(input);
|
||||
|
@ -175,11 +165,7 @@ public class ClientAttributeCertificateResource {
|
|||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public CertificateRepresentation uploadJksCertificate(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
try {
|
||||
CertificateRepresentation info = getCertFromRequest(input);
|
||||
|
@ -194,10 +180,12 @@ public class ClientAttributeCertificateResource {
|
|||
}
|
||||
|
||||
private CertificateRepresentation getCertFromRequest(MultipartFormDataInput input) throws IOException {
|
||||
auth.requireManage();
|
||||
auth.clients().requireManage(client);
|
||||
CertificateRepresentation info = new CertificateRepresentation();
|
||||
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
|
||||
String keystoreFormat = uploadForm.get("keystoreFormat").get(0).getBodyAsString();
|
||||
List<InputPart> keystoreFormatPart = uploadForm.get("keystoreFormat");
|
||||
if (keystoreFormatPart == null) throw new BadRequestException();
|
||||
String keystoreFormat = keystoreFormatPart.get(0).getBodyAsString();
|
||||
List<InputPart> inputParts = uploadForm.get("file");
|
||||
if (keystoreFormat.equals(CERTIFICATE_PEM)) {
|
||||
String pem = StreamUtil.readString(inputParts.get(0).getBody(InputStream.class, null));
|
||||
|
@ -279,11 +267,7 @@ public class ClientAttributeCertificateResource {
|
|||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public byte[] getKeystore(final KeyStoreConfig config) {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
if (config.getFormat() != null && !config.getFormat().equals("JKS") && !config.getFormat().equals("PKCS12")) {
|
||||
throw new NotAcceptableException("Only support jks or pkcs12 format.");
|
||||
|
@ -322,11 +306,7 @@ public class ClientAttributeCertificateResource {
|
|||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public byte[] generateAndGetKeystore(final KeyStoreConfig config) {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
if (config.getFormat() != null && !config.getFormat().equals("JKS") && !config.getFormat().equals("PKCS12")) {
|
||||
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.ClientInitialAccessPresentation;
|
||||
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -48,7 +49,7 @@ import java.util.List;
|
|||
*/
|
||||
public class ClientInitialAccessResource {
|
||||
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
private final RealmModel realm;
|
||||
private final AdminEventBuilder adminEvent;
|
||||
|
||||
|
@ -58,12 +59,11 @@ public class ClientInitialAccessResource {
|
|||
@Context
|
||||
protected UriInfo uriInfo;
|
||||
|
||||
public ClientInitialAccessResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ClientInitialAccessResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.auth = auth;
|
||||
this.realm = realm;
|
||||
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)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public ClientInitialAccessPresentation create(ClientInitialAccessCreatePresentation config, @Context final HttpServletResponse response) {
|
||||
auth.requireManage();
|
||||
auth.clients().requireManage();
|
||||
|
||||
int expiration = config.getExpiration() != null ? config.getExpiration() : 0;
|
||||
int count = config.getCount() != null ? config.getCount() : 1;
|
||||
|
@ -99,7 +99,7 @@ public class ClientInitialAccessResource {
|
|||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<ClientInitialAccessPresentation> list() {
|
||||
auth.requireView();
|
||||
auth.clients().requireView();
|
||||
|
||||
List<ClientInitialAccessModel> models = session.realms().listClientInitialAccess(realm);
|
||||
List<ClientInitialAccessPresentation> reps = new LinkedList<>();
|
||||
|
@ -113,7 +113,7 @@ public class ClientInitialAccessResource {
|
|||
@DELETE
|
||||
@Path("{id}")
|
||||
public void delete(final @PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
auth.clients().requireManage();
|
||||
|
||||
session.realms().removeClientInitialAccessModel(realm, id);
|
||||
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.services.clientregistration.policy.ClientRegistrationPolicy;
|
||||
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyFactory;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
/**
|
||||
* @resource Client Registration Policy
|
||||
|
@ -44,7 +45,7 @@ import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyF
|
|||
*/
|
||||
public class ClientRegistrationPolicyResource {
|
||||
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
private final RealmModel realm;
|
||||
private final AdminEventBuilder adminEvent;
|
||||
|
||||
|
@ -54,12 +55,11 @@ public class ClientRegistrationPolicyResource {
|
|||
@Context
|
||||
protected UriInfo uriInfo;
|
||||
|
||||
public ClientRegistrationPolicyResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ClientRegistrationPolicyResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.auth = auth;
|
||||
this.realm = realm;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
|
||||
|
||||
auth.init(RealmAuth.Resource.CLIENT);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,10 +27,12 @@ import org.keycloak.events.admin.OperationType;
|
|||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
|
@ -40,7 +42,9 @@ import org.keycloak.models.utils.RepresentationToModel;
|
|||
import org.keycloak.protocol.ClientInstallationProvider;
|
||||
import org.keycloak.representations.adapters.action.GlobalRequestResult;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
|
@ -51,6 +55,9 @@ import org.keycloak.services.managers.ClientManager;
|
|||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.services.validation.ClientValidator;
|
||||
import org.keycloak.services.validation.PairwiseClientValidator;
|
||||
import org.keycloak.services.validation.ValidationMessages;
|
||||
|
@ -89,7 +96,7 @@ import static java.lang.Boolean.TRUE;
|
|||
public class ClientResource {
|
||||
protected static final Logger logger = Logger.getLogger(ClientResource.class);
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
private AdminEventBuilder adminEvent;
|
||||
protected ClientModel client;
|
||||
protected KeycloakSession session;
|
||||
|
@ -104,19 +111,19 @@ public class ClientResource {
|
|||
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.auth = auth;
|
||||
this.client = clientModel;
|
||||
this.session = session;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.CLIENT);
|
||||
|
||||
auth.init(RealmAuth.Resource.CLIENT);
|
||||
}
|
||||
|
||||
@Path("protocol-mappers")
|
||||
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);
|
||||
return mappers;
|
||||
}
|
||||
|
@ -129,15 +136,11 @@ public class ClientResource {
|
|||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response update(final ClientRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
ValidationMessages validationMessages = new 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(
|
||||
validationMessages.getStringMessages(),
|
||||
validationMessages.getStringMessages(messages),
|
||||
|
@ -164,17 +167,14 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public ClientRepresentation getClient() {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
ClientRepresentation representation = ModelToRepresentation.toRepresentation(client);
|
||||
|
||||
if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
|
||||
representation.setAuthorizationServicesEnabled(authorization().isEnabled());
|
||||
}
|
||||
representation.setAccess(auth.clients().getAccess(client));
|
||||
|
||||
return representation;
|
||||
}
|
||||
|
@ -194,11 +194,7 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Path("installation/providers/{providerId}")
|
||||
public Response getInstallationProvider(@PathParam("providerId") String providerId) {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
ClientInstallationProvider provider = session.getProvider(ClientInstallationProvider.class, providerId);
|
||||
if (provider == null) throw new NotFoundException("Unknown Provider");
|
||||
|
@ -212,7 +208,7 @@ public class ClientResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public void deleteClient() {
|
||||
auth.requireManage();
|
||||
auth.clients().requireManage(client);
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
|
@ -233,11 +229,7 @@ public class ClientResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public CredentialRepresentation regenerateSecret() {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
logger.debug("regenerateSecret");
|
||||
UserCredentialModel cred = KeycloakModelUtils.generateSecret(client);
|
||||
|
@ -256,11 +248,7 @@ public class ClientResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public ClientRepresentation regenerateRegistrationAccessToken() {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireManage(client);
|
||||
|
||||
String token = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, realm, uriInfo, client, RegistrationAuth.AUTHENTICATED);
|
||||
|
||||
|
@ -281,11 +269,7 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public CredentialRepresentation getClientSecret() {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
logger.debug("getClientSecret");
|
||||
UserCredentialModel model = UserCredentialModel.secret(client.getSecret());
|
||||
|
@ -300,12 +284,14 @@ public class ClientResource {
|
|||
*/
|
||||
@Path("scope-mappings")
|
||||
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")
|
||||
public RoleContainerResource getRoleContainerResource() {
|
||||
return new RoleContainerResource(uriInfo, realm, auth, client, adminEvent);
|
||||
return new RoleContainerResource(session, uriInfo, realm, auth, client, adminEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -318,11 +304,7 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public UserRepresentation getServiceAccountUser() {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
UserModel user = session.users().getServiceAccount(client);
|
||||
if (user == null) {
|
||||
|
@ -346,11 +328,7 @@ public class ClientResource {
|
|||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public GlobalRequestResult pushRevocation() {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).resource(ResourceType.CLIENT).success();
|
||||
return new ResourceAdminManager(session).pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client);
|
||||
|
@ -373,11 +351,7 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Map<String, Long> getApplicationSessionCount() {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
Map<String, Long> map = new HashMap<>();
|
||||
map.put("count", session.sessions().getActiveUserSessions(client.getRealm(), client));
|
||||
|
@ -398,11 +372,7 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<UserSessionRepresentation> getUserSessions(@QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
firstResult = firstResult != null ? firstResult : -1;
|
||||
maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
|
||||
|
@ -430,11 +400,7 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Map<String, Long> getOfflineSessionCount() {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
Map<String, Long> map = new HashMap<>();
|
||||
map.put("count", session.sessions().getOfflineSessionsCount(client.getRealm(), client));
|
||||
|
@ -455,11 +421,7 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<UserSessionRepresentation> getOfflineUserSessions(@QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
|
||||
auth.requireView();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireView(client);
|
||||
|
||||
firstResult = firstResult != null ? firstResult : -1;
|
||||
maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
|
||||
|
@ -496,11 +458,7 @@ public class ClientResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void registerNode(Map<String, String> formParams) {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
String node = formParams.get("node");
|
||||
if (node == null) {
|
||||
|
@ -520,11 +478,7 @@ public class ClientResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public void unregisterNode(final @PathParam("node") String node) {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
if (logger.isDebugEnabled()) logger.debug("Unregister node: " + node);
|
||||
|
||||
|
@ -548,11 +502,7 @@ public class ClientResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public GlobalRequestResult testNodesAvailable() {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.clients().requireConfigure(client);
|
||||
|
||||
logger.debug("Test availability of cluster nodes");
|
||||
GlobalRequestResult result = new ResourceAdminManager(session).testNodesAvailability(uriInfo.getRequestUri(), realm, client);
|
||||
|
@ -571,6 +521,57 @@ public class ClientResource {
|
|||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object stating whether client Authorization permissions have been initialized or not and a reference
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("management/permissions")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ManagementPermissionReference getManagementPermissions() {
|
||||
auth.roles().requireView(client);
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
if (!permissions.clients().isPermissionsEnabled(client)) {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
return toMgmtRef(client, permissions);
|
||||
}
|
||||
|
||||
public static ManagementPermissionReference toMgmtRef(ClientModel client, AdminPermissionManagement permissions) {
|
||||
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||
ref.setEnabled(true);
|
||||
ref.setResource(permissions.clients().resource(client).getId());
|
||||
ref.setScopePermissions(permissions.clients().getPermissions(client));
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return object stating whether client Authorization permissions have been initialized or not and a reference
|
||||
*
|
||||
*
|
||||
* @return initialized manage permissions reference
|
||||
*/
|
||||
@Path("management/permissions")
|
||||
@PUT
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
|
||||
auth.clients().requireManage(client);
|
||||
if (ref.isEnabled()) {
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
permissions.clients().setPermissionsEnabled(client, ref.isEnabled());
|
||||
return toMgmtRef(client, permissions);
|
||||
} else {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateClientFromRep(ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException {
|
||||
if (TRUE.equals(rep.isServiceAccountsEnabled())) {
|
||||
UserModel serviceAccount = this.session.users().getServiceAccount(client);
|
||||
|
@ -584,6 +585,30 @@ public class ClientResource {
|
|||
new ClientManager(new RealmManager(session)).clientIdChanged(client, rep.getClientId());
|
||||
}
|
||||
|
||||
if (rep.isFullScopeAllowed() != null && rep.isFullScopeAllowed().booleanValue() != client.isFullScopeAllowed()) {
|
||||
auth.clients().requireManage(client);
|
||||
}
|
||||
|
||||
if (rep.getClientTemplate() != null) {
|
||||
ClientTemplateModel currTemplate = client.getClientTemplate();
|
||||
if (currTemplate == null) {
|
||||
if (!rep.getClientTemplate().equals(ClientTemplateRepresentation.NONE)) {
|
||||
auth.clients().requireManage(client);
|
||||
}
|
||||
} else if (!rep.getClientTemplate().equals(currTemplate.getName())){
|
||||
auth.clients().requireManage(client);
|
||||
}
|
||||
if ((rep.isUseTemplateConfig() != null && rep.isUseTemplateConfig().booleanValue() != client.useTemplateConfig())
|
||||
|| (rep.isUseTemplateScope() != null && rep.isUseTemplateScope().booleanValue() != client.useTemplateScope())
|
||||
|| (rep.isUseTemplateMappers() != null && rep.isUseTemplateMappers().booleanValue() != client.useTemplateMappers())
|
||||
|
||||
) {
|
||||
auth.clients().requireManage(client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
RepresentationToModel.updateClient(rep, client);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
|
@ -30,6 +31,7 @@ import org.keycloak.models.RoleModel;
|
|||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.ForbiddenException;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
|
@ -47,6 +49,7 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @resource Client Role Mappings
|
||||
|
@ -58,19 +61,26 @@ public class ClientRoleMappingsResource {
|
|||
|
||||
protected KeycloakSession session;
|
||||
protected RealmModel realm;
|
||||
protected RealmAuth auth;
|
||||
protected AdminPermissionEvaluator auth;
|
||||
protected RoleMapperModel user;
|
||||
protected ClientModel client;
|
||||
protected AdminEventBuilder adminEvent;
|
||||
private UriInfo uriInfo;
|
||||
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.session = session;
|
||||
this.realm = realm;
|
||||
this.auth = auth;
|
||||
this.user = user;
|
||||
this.client = client;
|
||||
this.managePermission = manageCheck;
|
||||
this.viewPermission = viewCheck;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_ROLE_MAPPING);
|
||||
}
|
||||
|
||||
|
@ -83,11 +93,7 @@ public class ClientRoleMappingsResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getClientRoleMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (user == null || client == null) {
|
||||
throw new NotFoundException("Not found");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
Set<RoleModel> mappings = user.getClientRoleMappings(client);
|
||||
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
||||
|
@ -109,11 +115,8 @@ public class ClientRoleMappingsResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getCompositeClientRoleMappings() {
|
||||
auth.requireView();
|
||||
viewPermission.require();
|
||||
|
||||
if (user == null || client == null) {
|
||||
throw new NotFoundException("Not found");
|
||||
}
|
||||
|
||||
Set<RoleModel> roles = client.getRoles();
|
||||
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
||||
|
@ -133,13 +136,12 @@ public class ClientRoleMappingsResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getAvailableClientRoleMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (user == null || client == null) {
|
||||
throw new NotFoundException("Not found");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
Set<RoleModel> available = client.getRoles();
|
||||
available = available.stream().filter(r ->
|
||||
auth.roles().canMapRole(r)
|
||||
).collect(Collectors.toSet());
|
||||
return getAvailableRoles(user, available);
|
||||
}
|
||||
|
||||
|
@ -165,17 +167,14 @@ public class ClientRoleMappingsResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void addClientRoleMapping(List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
if (user == null || client == null) {
|
||||
throw new NotFoundException("Not found");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
for (RoleRepresentation role : roles) {
|
||||
RoleModel roleModel = client.getRole(role.getName());
|
||||
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
||||
throw new NotFoundException("Role not found");
|
||||
}
|
||||
auth.roles().requireMapRole(roleModel);
|
||||
user.grantRole(roleModel);
|
||||
}
|
||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
|
||||
|
@ -183,18 +182,14 @@ public class ClientRoleMappingsResource {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete client-level roles from user role mapping
|
||||
*
|
||||
* @param roles
|
||||
*/
|
||||
* Delete client-level roles from user role mapping
|
||||
*
|
||||
* @param roles
|
||||
*/
|
||||
@DELETE
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void deleteClientRoleMapping(List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
if (user == null || client == null) {
|
||||
throw new NotFoundException("Not found");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
if (roles == null) {
|
||||
Set<RoleModel> roleModels = user.getClientRoleMappings(client);
|
||||
|
@ -205,6 +200,7 @@ public class ClientRoleMappingsResource {
|
|||
ClientModel client = (ClientModel) roleModel.getContainer();
|
||||
if (!client.getId().equals(this.client.getId())) continue;
|
||||
}
|
||||
auth.roles().requireMapRole(roleModel);
|
||||
user.deleteRoleMapping(roleModel);
|
||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
||||
}
|
||||
|
@ -216,10 +212,11 @@ public class ClientRoleMappingsResource {
|
|||
throw new NotFoundException("Role not found");
|
||||
}
|
||||
|
||||
auth.roles().requireMapRole(roleModel);
|
||||
try {
|
||||
user.deleteRoleMapping(roleModel);
|
||||
} 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()),
|
||||
Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
|
|||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
|
@ -54,7 +55,7 @@ import javax.ws.rs.core.UriInfo;
|
|||
public class ClientTemplateResource {
|
||||
protected static final Logger logger = Logger.getLogger(ClientTemplateResource.class);
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
private AdminEventBuilder adminEvent;
|
||||
protected ClientTemplateModel template;
|
||||
protected KeycloakSession session;
|
||||
|
@ -62,19 +63,20 @@ public class ClientTemplateResource {
|
|||
@Context
|
||||
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.auth = auth;
|
||||
this.template = template;
|
||||
this.session = session;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE);
|
||||
|
||||
auth.init(RealmAuth.Resource.CLIENT);
|
||||
}
|
||||
|
||||
@Path("protocol-mappers")
|
||||
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);
|
||||
return mappers;
|
||||
}
|
||||
|
@ -86,7 +88,9 @@ public class ClientTemplateResource {
|
|||
*/
|
||||
@Path("scope-mappings")
|
||||
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
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response update(final ClientTemplateRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
if (template == null) {
|
||||
throw new NotFoundException("Could not find client template");
|
||||
}
|
||||
auth.clients().requireManageTemplates();
|
||||
|
||||
try {
|
||||
RepresentationToModel.updateClientTemplate(rep, template);
|
||||
|
@ -125,11 +125,8 @@ public class ClientTemplateResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public ClientTemplateRepresentation getClient() {
|
||||
auth.requireView();
|
||||
auth.clients().requireView(template);
|
||||
|
||||
if (template == null) {
|
||||
throw new NotFoundException("Could not find client template");
|
||||
}
|
||||
|
||||
return ModelToRepresentation.toRepresentation(template);
|
||||
}
|
||||
|
@ -141,11 +138,7 @@ public class ClientTemplateResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public Response deleteClientTemplate() {
|
||||
auth.requireManage();
|
||||
|
||||
if (template == null) {
|
||||
throw new NotFoundException("Could not find client template");
|
||||
}
|
||||
auth.clients().requireManage(template);
|
||||
|
||||
try {
|
||||
realm.removeClientTemplate(template.getId());
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.keycloak.services.resources.admin;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
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.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
|
@ -53,18 +55,16 @@ import java.util.List;
|
|||
public class ClientTemplatesResource {
|
||||
protected static final Logger logger = Logger.getLogger(ClientTemplatesResource.class);
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
||||
@Context
|
||||
protected KeycloakSession session;
|
||||
|
||||
public ClientTemplatesResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ClientTemplatesResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.realm = realm;
|
||||
this.auth = auth;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE);
|
||||
|
||||
auth.init(RealmAuth.Resource.CLIENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,22 +76,19 @@ public class ClientTemplatesResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<ClientTemplateRepresentation> getClientTemplates() {
|
||||
auth.requireView();
|
||||
auth.clients().requireListTemplates();
|
||||
|
||||
List<ClientTemplateRepresentation> rep = new ArrayList<>();
|
||||
List<ClientTemplateModel> clientModels = realm.getClientTemplates();
|
||||
|
||||
boolean view = auth.hasView();
|
||||
boolean viewable = auth.clients().canViewTemplates();
|
||||
for (ClientTemplateModel clientModel : clientModels) {
|
||||
if (view) {
|
||||
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);
|
||||
if (viewable) rep.add(ModelToRepresentation.toRepresentation(clientModel));
|
||||
else {
|
||||
ClientTemplateRepresentation tempRep = new ClientTemplateRepresentation();
|
||||
tempRep.setName(clientModel.getName());
|
||||
tempRep.setId(clientModel.getId());
|
||||
tempRep.setProtocol(clientModel.getProtocol());
|
||||
}
|
||||
}
|
||||
return rep;
|
||||
|
@ -109,7 +106,7 @@ public class ClientTemplatesResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response createClientTemplate(final @Context UriInfo uriInfo, final ClientTemplateRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.clients().requireManageTemplates();
|
||||
|
||||
try {
|
||||
ClientTemplateModel clientModel = RepresentationToModel.createClientTemplate(session, realm, rep);
|
||||
|
@ -130,7 +127,11 @@ public class ClientTemplatesResource {
|
|||
*/
|
||||
@Path("{id}")
|
||||
public ClientTemplateResource getClient(final @PathParam("id") String id) {
|
||||
auth.clients().requireListTemplates();
|
||||
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);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(clientResource);
|
||||
return clientResource;
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.keycloak.common.Profile;
|
|||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -34,14 +35,18 @@ import org.keycloak.models.utils.ModelToRepresentation;
|
|||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.ForbiddenException;
|
||||
import org.keycloak.services.managers.ClientManager;
|
||||
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.PairwiseClientValidator;
|
||||
import org.keycloak.services.validation.ValidationMessages;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
|
@ -65,18 +70,17 @@ import java.util.Properties;
|
|||
public class ClientsResource {
|
||||
protected static final Logger logger = Logger.getLogger(ClientsResource.class);
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
||||
@Context
|
||||
protected KeycloakSession session;
|
||||
|
||||
public ClientsResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ClientsResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.realm = realm;
|
||||
this.auth = auth;
|
||||
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
|
||||
*
|
||||
* @param clientId filter by clientId
|
||||
* @param viewableOnly filter clients that cannot be viewed in full by admin
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<ClientRepresentation> getClients(@QueryParam("clientId") String clientId) {
|
||||
auth.requireAny();
|
||||
|
||||
public List<ClientRepresentation> getClients(@QueryParam("clientId") String clientId, @QueryParam("viewableOnly") @DefaultValue("false") boolean viewableOnly) {
|
||||
List<ClientRepresentation> rep = new ArrayList<>();
|
||||
|
||||
if (clientId == null) {
|
||||
List<ClientModel> clientModels = realm.getClients();
|
||||
|
||||
boolean view = auth.hasView();
|
||||
auth.clients().requireList();
|
||||
boolean view = auth.clients().canView();
|
||||
for (ClientModel clientModel : clientModels) {
|
||||
if (view) {
|
||||
if (view || auth.clients().canView(clientModel)) {
|
||||
ClientRepresentation representation = ModelToRepresentation.toRepresentation(clientModel);
|
||||
|
||||
if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
|
||||
|
@ -111,7 +114,8 @@ public class ClientsResource {
|
|||
}
|
||||
|
||||
rep.add(representation);
|
||||
} else {
|
||||
representation.setAccess(auth.clients().getAccess(clientModel));
|
||||
} else if (!viewableOnly) {
|
||||
ClientRepresentation client = new ClientRepresentation();
|
||||
client.setId(clientModel.getId());
|
||||
client.setClientId(clientModel.getClientId());
|
||||
|
@ -120,9 +124,22 @@ public class ClientsResource {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
if (client != null) {
|
||||
rep.add(ModelToRepresentation.toRepresentation(client));
|
||||
ClientModel clientModel = realm.getClientByClientId(clientId);
|
||||
if (clientModel != null) {
|
||||
if (auth.clients().canView(clientModel)) {
|
||||
ClientRepresentation representation = ModelToRepresentation.toRepresentation(clientModel);
|
||||
representation.setAccess(auth.clients().getAccess(clientModel));
|
||||
rep.add(representation);
|
||||
} 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;
|
||||
|
@ -144,11 +161,11 @@ public class ClientsResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response createClient(final @Context UriInfo uriInfo, final ClientRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.clients().requireManage();
|
||||
|
||||
ValidationMessages validationMessages = new 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(
|
||||
validationMessages.getStringMessages(),
|
||||
validationMessages.getStringMessages(messages),
|
||||
|
@ -189,7 +206,13 @@ public class ClientsResource {
|
|||
*/
|
||||
@Path("{id}")
|
||||
public ClientResource getClient(final @PathParam("id") String id) {
|
||||
|
||||
ClientModel clientModel = realm.getClientById(id);
|
||||
if (clientModel == null) {
|
||||
// we do this to make sure somebody can't phish ids
|
||||
if (auth.clients().canList()) throw new NotFoundException("Could not find client");
|
||||
else throw new ForbiddenException();
|
||||
}
|
||||
|
||||
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.ConfigPropertyRepresentation;
|
||||
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.Consumes;
|
||||
|
@ -63,7 +63,6 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @resource Component
|
||||
|
@ -75,7 +74,7 @@ public class ComponentResource {
|
|||
|
||||
protected RealmModel realm;
|
||||
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
||||
|
@ -91,12 +90,10 @@ public class ComponentResource {
|
|||
@Context
|
||||
protected HttpHeaders headers;
|
||||
|
||||
public ComponentResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ComponentResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.auth = auth;
|
||||
this.realm = realm;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.COMPONENT);
|
||||
|
||||
auth.init(RealmAuth.Resource.REALM);
|
||||
}
|
||||
|
||||
@GET
|
||||
|
@ -105,7 +102,7 @@ public class ComponentResource {
|
|||
public List<ComponentRepresentation> getComponents(@QueryParam("parent") String parent,
|
||||
@QueryParam("type") String type,
|
||||
@QueryParam("name") String name) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
List<ComponentModel> components = Collections.EMPTY_LIST;
|
||||
if (parent == null && type == null) {
|
||||
components = realm.getComponents();
|
||||
|
@ -135,7 +132,7 @@ public class ComponentResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response create(ComponentRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
try {
|
||||
ComponentModel model = RepresentationToModel.toModel(session, rep);
|
||||
if (model.getParentId() == null) model.setParentId(realm.getId());
|
||||
|
@ -156,7 +153,7 @@ public class ComponentResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ComponentRepresentation getComponent(@PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
ComponentModel model = realm.getComponent(id);
|
||||
if (model == null) {
|
||||
throw new NotFoundException("Could not find component");
|
||||
|
@ -169,7 +166,7 @@ public class ComponentResource {
|
|||
@Path("{id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response updateComponent(@PathParam("id") String id, ComponentRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
try {
|
||||
ComponentModel model = realm.getComponent(id);
|
||||
if (model == null) {
|
||||
|
@ -188,7 +185,7 @@ public class ComponentResource {
|
|||
@DELETE
|
||||
@Path("{id}")
|
||||
public void removeComponent(@PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
ComponentModel model = realm.getComponent(id);
|
||||
if (model == null) {
|
||||
throw new NotFoundException("Could not find component");
|
||||
|
@ -199,7 +196,7 @@ public class ComponentResource {
|
|||
}
|
||||
|
||||
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) -> {
|
||||
|
||||
|
@ -228,7 +225,7 @@ public class ComponentResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<ComponentTypeRepresentation> getSubcomponentConfig(@PathParam("id") String parentId, @QueryParam("type") String subtype) {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
ComponentModel parent = realm.getComponent(parentId);
|
||||
if (parent == null) {
|
||||
throw new NotFoundException("Could not find parent component");
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.jboss.resteasy.spi.NotFoundException;
|
|||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -28,6 +29,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -49,6 +51,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
|
||||
/**
|
||||
* @resource Groups
|
||||
|
@ -58,11 +63,11 @@ public class GroupResource {
|
|||
|
||||
private final RealmModel realm;
|
||||
private final KeycloakSession session;
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
private final AdminEventBuilder adminEvent;
|
||||
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.session = session;
|
||||
this.auth = auth;
|
||||
|
@ -72,7 +77,7 @@ public class GroupResource {
|
|||
|
||||
@Context private UriInfo uriInfo;
|
||||
|
||||
/**
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return
|
||||
|
@ -81,13 +86,13 @@ public class GroupResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public GroupRepresentation getGroup() {
|
||||
this.auth.requireView();
|
||||
this.auth.groups().requireView(group);
|
||||
|
||||
if (group == null) {
|
||||
throw new NotFoundException("Could not find group by id");
|
||||
}
|
||||
GroupRepresentation rep = ModelToRepresentation.toGroupHierarchy(group, true);
|
||||
|
||||
return ModelToRepresentation.toGroupHierarchy(group, true);
|
||||
rep.setAccess(auth.groups().getAccess(group));
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,11 +103,7 @@ public class GroupResource {
|
|||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void updateGroup(GroupRepresentation rep) {
|
||||
this.auth.requireManage();
|
||||
|
||||
if (group == null) {
|
||||
throw new NotFoundException("Could not find group by id");
|
||||
}
|
||||
this.auth.groups().requireManage(group);
|
||||
|
||||
updateGroup(rep, group);
|
||||
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
||||
|
@ -112,11 +113,7 @@ public class GroupResource {
|
|||
|
||||
@DELETE
|
||||
public void deleteGroup() {
|
||||
this.auth.requireManage();
|
||||
|
||||
if (group == null) {
|
||||
throw new NotFoundException("Could not find group by id");
|
||||
}
|
||||
this.auth.groups().requireManage(group);
|
||||
|
||||
realm.removeGroup(group);
|
||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||
|
@ -135,12 +132,8 @@ public class GroupResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
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()) {
|
||||
if (group.getName().equals(rep.getName())) {
|
||||
return ErrorResponse.exists("Parent already contains subgroup named '" + rep.getName() + "'");
|
||||
|
@ -191,9 +184,9 @@ public class GroupResource {
|
|||
|
||||
@Path("role-mappings")
|
||||
public RoleMapperResource getRoleMappings() {
|
||||
auth.init(RealmAuth.Resource.USER);
|
||||
|
||||
RoleMapperResource resource = new RoleMapperResource(realm, auth, group, adminEvent);
|
||||
AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.groups().requireManage(group);
|
||||
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.groups().requireView(group);
|
||||
RoleMapperResource resource = new RoleMapperResource(realm, auth, group, adminEvent, manageCheck, viewCheck);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
return resource;
|
||||
|
||||
|
@ -214,11 +207,8 @@ public class GroupResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<UserRepresentation> getMembers(@QueryParam("first") Integer firstResult,
|
||||
@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;
|
||||
maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
|
||||
|
@ -232,4 +222,55 @@ public class GroupResource {
|
|||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object stating whether client Authorization permissions have been initialized or not and a reference
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("management/permissions")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ManagementPermissionReference getManagementPermissions() {
|
||||
auth.groups().requireView(group);
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
if (!permissions.groups().isPermissionsEnabled(group)) {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
return toMgmtRef(group, permissions);
|
||||
}
|
||||
|
||||
public static ManagementPermissionReference toMgmtRef(GroupModel group, AdminPermissionManagement permissions) {
|
||||
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||
ref.setEnabled(true);
|
||||
ref.setResource(permissions.groups().resource(group).getId());
|
||||
ref.setScopePermissions(permissions.groups().getPermissions(group));
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return object stating whether client Authorization permissions have been initialized or not and a reference
|
||||
*
|
||||
*
|
||||
* @return initialized manage permissions reference
|
||||
*/
|
||||
@Path("management/permissions")
|
||||
@PUT
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
|
||||
auth.groups().requireManage(group);
|
||||
if (ref.isEnabled()) {
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
permissions.groups().setPermissionsEnabled(group, ref.isEnabled());
|
||||
return toMgmtRef(group, permissions);
|
||||
} else {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import javax.ws.rs.core.UriInfo;
|
|||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
/**
|
||||
* @resource Groups
|
||||
|
@ -49,15 +50,14 @@ public class GroupsResource {
|
|||
|
||||
private final RealmModel realm;
|
||||
private final KeycloakSession session;
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
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.session = session;
|
||||
this.auth = auth;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.GROUP);
|
||||
auth.init(RealmAuth.Resource.USER);
|
||||
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ public class GroupsResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<GroupRepresentation> getGroups() {
|
||||
auth.requireView();
|
||||
auth.groups().requireList();
|
||||
|
||||
return ModelToRepresentation.toGroupHierarchy(realm, false);
|
||||
}
|
||||
|
@ -85,9 +85,10 @@ public class GroupsResource {
|
|||
*/
|
||||
@Path("{id}")
|
||||
public GroupResource getGroupById(@PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
|
||||
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);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
return resource;
|
||||
|
@ -102,7 +103,7 @@ public class GroupsResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response addTopLevelGroup(GroupRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.groups().requireManage();
|
||||
|
||||
for (GroupModel group : realm.getGroups()) {
|
||||
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.IdentityProviderRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
|
@ -72,7 +73,7 @@ public class IdentityProviderResource {
|
|||
|
||||
protected static final Logger logger = Logger.getLogger(IdentityProviderResource.class);
|
||||
|
||||
private final RealmAuth auth;
|
||||
private final AdminPermissionEvaluator auth;
|
||||
private final RealmModel realm;
|
||||
private final KeycloakSession session;
|
||||
private final IdentityProviderModel identityProviderModel;
|
||||
|
@ -80,7 +81,7 @@ public class IdentityProviderResource {
|
|||
|
||||
@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.session = session;
|
||||
this.identityProviderModel = identityProviderModel;
|
||||
|
@ -97,7 +98,7 @@ public class IdentityProviderResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public IdentityProviderRepresentation getIdentityProvider() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -115,7 +116,7 @@ public class IdentityProviderResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public Response delete() {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -138,7 +139,7 @@ public class IdentityProviderResource {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response update(IdentityProviderRepresentation providerRep) {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -229,7 +230,7 @@ public class IdentityProviderResource {
|
|||
@Path("export")
|
||||
@NoCache
|
||||
public Response export(@Context UriInfo uriInfo, @QueryParam("format") String format) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -250,7 +251,7 @@ public class IdentityProviderResource {
|
|||
@Path("mapper-types")
|
||||
@NoCache
|
||||
public Map<String, IdentityProviderMapperTypeRepresentation> getMapperTypes() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -289,7 +290,7 @@ public class IdentityProviderResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<IdentityProviderMapperRepresentation> getMappers() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -312,7 +313,7 @@ public class IdentityProviderResource {
|
|||
@Path("mappers")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response addMapper(IdentityProviderMapperRepresentation mapper) {
|
||||
auth.requireManage();
|
||||
this.auth.realm().requireManageIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -343,7 +344,7 @@ public class IdentityProviderResource {
|
|||
@Path("mappers/{id}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public IdentityProviderMapperRepresentation getMapperById(@PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -365,7 +366,7 @@ public class IdentityProviderResource {
|
|||
@Path("mappers/{id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void update(@PathParam("id") String id, IdentityProviderMapperRepresentation rep) {
|
||||
auth.requireManage();
|
||||
this.auth.realm().requireManageIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
@ -388,7 +389,7 @@ public class IdentityProviderResource {
|
|||
@NoCache
|
||||
@Path("mappers/{id}")
|
||||
public void delete(@PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
this.auth.realm().requireManageIdentityProviders();
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
throw new javax.ws.rs.NotFoundException();
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.keycloak.models.utils.StripSecretsUtils;
|
|||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -65,14 +66,13 @@ public class IdentityProvidersResource {
|
|||
|
||||
private final RealmModel realm;
|
||||
private final KeycloakSession session;
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
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.session = session;
|
||||
this.auth = auth;
|
||||
this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER);
|
||||
this.adminEvent = adminEvent.resource(ResourceType.IDENTITY_PROVIDER);
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class IdentityProvidersResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getIdentityProviders(@PathParam("provider_id") String providerId) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
|
||||
if (providerFactory != null) {
|
||||
return Response.ok(providerFactory).build();
|
||||
|
@ -108,7 +108,7 @@ public class IdentityProvidersResource {
|
|||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
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();
|
||||
if (!(formDataMap.containsKey("providerId") && formDataMap.containsKey("file"))) {
|
||||
throw new BadRequestException();
|
||||
|
@ -134,7 +134,7 @@ public class IdentityProvidersResource {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
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"))) {
|
||||
throw new BadRequestException();
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ public class IdentityProvidersResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<IdentityProviderRepresentation> getIdentityProviders() {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
|
||||
List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>();
|
||||
|
||||
|
@ -185,7 +185,7 @@ public class IdentityProvidersResource {
|
|||
@Path("instances")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response create(@Context UriInfo uriInfo, IdentityProviderRepresentation representation) {
|
||||
this.auth.requireManage();
|
||||
this.auth.realm().requireManageIdentityProviders();
|
||||
|
||||
try {
|
||||
IdentityProviderModel identityProvider = RepresentationToModel.toModel(realm, representation);
|
||||
|
@ -203,7 +203,7 @@ public class IdentityProvidersResource {
|
|||
|
||||
@Path("instances/{alias}")
|
||||
public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) {
|
||||
this.auth.requireView();
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
IdentityProviderModel identityProviderModel = null;
|
||||
|
||||
for (IdentityProviderModel storedIdentityProvider : this.realm.getIdentityProviders()) {
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.KeyManager;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.KeysMetadataRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Produces;
|
||||
|
@ -43,9 +44,9 @@ public class KeyResource {
|
|||
|
||||
private RealmModel realm;
|
||||
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.session = session;
|
||||
this.auth = auth;
|
||||
|
@ -55,7 +56,7 @@ public class KeyResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public KeysMetadataRepresentation getKeyMetadata() {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
KeyManager keystore = session.keys();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.keycloak.protocol.ProtocolMapperConfigException;
|
|||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
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.DELETE;
|
||||
|
@ -66,7 +66,9 @@ public class ProtocolMappersResource {
|
|||
|
||||
protected ProtocolMapperContainerModel client;
|
||||
|
||||
protected RealmAuth auth;
|
||||
protected AdminPermissionEvaluator auth;
|
||||
protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
|
||||
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
|
||||
|
||||
protected AdminEventBuilder adminEvent;
|
||||
|
||||
|
@ -76,13 +78,17 @@ public class ProtocolMappersResource {
|
|||
@Context
|
||||
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.auth = auth;
|
||||
this.client = client;
|
||||
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}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<ProtocolMapperRepresentation> getMappersPerProtocol(@PathParam("protocol") String protocol) {
|
||||
auth.requireAny();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
|
||||
for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
|
||||
|
@ -119,11 +121,7 @@ public class ProtocolMappersResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response createMapper(ProtocolMapperRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
ProtocolMapperModel model = null;
|
||||
try {
|
||||
|
@ -147,11 +145,7 @@ public class ProtocolMappersResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void createMapper(List<ProtocolMapperRepresentation> reps) {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
ProtocolMapperModel model = null;
|
||||
for (ProtocolMapperRepresentation rep : reps) {
|
||||
|
@ -172,11 +166,7 @@ public class ProtocolMappersResource {
|
|||
@Path("models")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<ProtocolMapperRepresentation> getMappers() {
|
||||
auth.requireAny();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
|
||||
for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
|
||||
|
@ -196,11 +186,7 @@ public class ProtocolMappersResource {
|
|||
@Path("models/{id}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public ProtocolMapperRepresentation getMapperById(@PathParam("id") String id) {
|
||||
auth.requireAny();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
ProtocolMapperModel model = client.getProtocolMapperById(id);
|
||||
if (model == null) throw new NotFoundException("Model not found");
|
||||
|
@ -218,11 +204,7 @@ public class ProtocolMappersResource {
|
|||
@Path("models/{id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void update(@PathParam("id") String id, ProtocolMapperRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
ProtocolMapperModel model = client.getProtocolMapperById(id);
|
||||
if (model == null) throw new NotFoundException("Model not found");
|
||||
|
@ -243,11 +225,7 @@ public class ProtocolMappersResource {
|
|||
@NoCache
|
||||
@Path("models/{id}")
|
||||
public void delete(@PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
ProtocolMapperModel model = client.getProtocolMapperById(id);
|
||||
if (model == null) throw new NotFoundException("Model not found");
|
||||
|
@ -261,10 +239,12 @@ public class ProtocolMappersResource {
|
|||
ProtocolMapper mapper = (ProtocolMapper)session.getKeycloakSessionFactory().getProviderFactory(ProtocolMapper.class, model.getProtocolMapper());
|
||||
if (mapper != null) {
|
||||
mapper.validateConfig(session, realm, client, model);
|
||||
} else {
|
||||
throw new NotFoundException("ProtocolMapper provider not found");
|
||||
}
|
||||
} catch (ProtocolMapperConfigException ex) {
|
||||
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()),
|
||||
Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ import org.jboss.resteasy.spi.NotFoundException;
|
|||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.KeyPairVerifier;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
|
@ -63,6 +66,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
|||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||
import org.keycloak.representations.idm.PartialImportRepresentation;
|
||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -72,7 +76,6 @@ import org.keycloak.services.managers.LDAPConnectionTestManager;
|
|||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||
import org.keycloak.services.resources.admin.RealmAuth.Resource;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -112,7 +115,7 @@ import static org.keycloak.models.utils.StripSecretsUtils.stripForExport;
|
|||
*/
|
||||
public class RealmAdminResource {
|
||||
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
|
||||
protected RealmAuth auth;
|
||||
protected AdminPermissionEvaluator auth;
|
||||
protected RealmModel realm;
|
||||
private TokenManager tokenManager;
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
@ -129,14 +132,11 @@ public class RealmAdminResource {
|
|||
@Context
|
||||
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.realm = realm;
|
||||
this.tokenManager = tokenManager;
|
||||
this.adminEvent = adminEvent.realm(realm).resource(ResourceType.REALM);
|
||||
|
||||
auth.init(RealmAuth.Resource.REALM);
|
||||
auth.requireAny();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,7 +149,7 @@ public class RealmAdminResource {
|
|||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public ClientRepresentation convertClientDescription(String description) {
|
||||
auth.init(Resource.CLIENT).requireManage();
|
||||
auth.clients().requireManage();
|
||||
|
||||
if (realm == null) {
|
||||
throw new NotFoundException("Realm not found.");
|
||||
|
@ -238,7 +238,7 @@ public class RealmAdminResource {
|
|||
*/
|
||||
@Path("roles")
|
||||
public RoleContainerResource getRoleContainerResource() {
|
||||
return new RoleContainerResource(uriInfo, realm, auth, realm, adminEvent);
|
||||
return new RoleContainerResource(session, uriInfo, realm, auth, realm, adminEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -252,15 +252,15 @@ public class RealmAdminResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RealmRepresentation getRealm() {
|
||||
if (auth.hasView()) {
|
||||
if (auth.realm().canViewRealm()) {
|
||||
return ModelToRepresentation.toRepresentation(realm, false);
|
||||
} else {
|
||||
auth.requireAny();
|
||||
auth.realm().requireViewRealmNameList();
|
||||
|
||||
RealmRepresentation rep = new RealmRepresentation();
|
||||
rep.setRealm(realm.getName());
|
||||
|
||||
if (auth.init(Resource.IDENTITY_PROVIDER).hasView()) {
|
||||
if (auth.realm().canViewIdentityProviders()) {
|
||||
RealmRepresentation r = ModelToRepresentation.toRepresentation(realm, false);
|
||||
rep.setIdentityProviders(r.getIdentityProviders());
|
||||
rep.setIdentityProviderMappers(r.getIdentityProviderMappers());
|
||||
|
@ -282,7 +282,7 @@ public class RealmAdminResource {
|
|||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response updateRealm(final RealmRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
logger.debug("updating realm: " + realm.getName());
|
||||
|
||||
|
@ -344,7 +344,7 @@ public class RealmAdminResource {
|
|||
*/
|
||||
@DELETE
|
||||
public void deleteRealm() {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
if (!new RealmManager(session).removeRealm(realm)) {
|
||||
throw new NotFoundException("Realm doesn't exist");
|
||||
|
@ -364,6 +364,50 @@ public class RealmAdminResource {
|
|||
return users;
|
||||
}
|
||||
|
||||
@NoCache
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("users-management-permissions")
|
||||
public ManagementPermissionReference getUserMgmtPermissions() {
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
if (permissions.users().isPermissionsEnabled()) {
|
||||
return toUsersMgmtRef(permissions);
|
||||
} else {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
@Path("users-management-permissions")
|
||||
public ManagementPermissionReference setUsersManagementPermissionsEnabled(ManagementPermissionReference ref) {
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
permissions.users().setPermissionsEnabled(ref.isEnabled());
|
||||
if (ref.isEnabled()) {
|
||||
return toUsersMgmtRef(permissions);
|
||||
} else {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static ManagementPermissionReference toUsersMgmtRef(AdminPermissionManagement permissions) {
|
||||
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||
ref.setEnabled(true);
|
||||
ref.setResource(permissions.users().resource().getId());
|
||||
Map<String, String> scopes = permissions.users().getPermissions();
|
||||
ref.setScopePermissions(scopes);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
@Path("user-storage")
|
||||
public UserStorageProviderResource userStorage() {
|
||||
UserStorageProviderResource fed = new UserStorageProviderResource(realm, auth, adminEvent);
|
||||
|
@ -388,7 +432,7 @@ public class RealmAdminResource {
|
|||
*/
|
||||
@Path("roles-by-id")
|
||||
public RoleByIdResource rolesById() {
|
||||
RoleByIdResource resource = new RoleByIdResource(realm, auth, adminEvent);
|
||||
RoleByIdResource resource = new RoleByIdResource(realm, auth, adminEvent);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
//resourceContext.initResource(resource);
|
||||
return resource;
|
||||
|
@ -401,7 +445,7 @@ public class RealmAdminResource {
|
|||
@Path("push-revocation")
|
||||
@POST
|
||||
public GlobalRequestResult pushRevocation() {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
GlobalRequestResult result = new ResourceAdminManager(session).pushRealmRevocationPolicy(uriInfo.getRequestUri(), realm);
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).representation(result).success();
|
||||
|
@ -416,7 +460,7 @@ public class RealmAdminResource {
|
|||
@Path("logout-all")
|
||||
@POST
|
||||
public GlobalRequestResult logoutAll() {
|
||||
auth.init(RealmAuth.Resource.USER).requireManage();
|
||||
auth.users().requireManage();
|
||||
|
||||
session.sessions().removeUserSessions(realm);
|
||||
GlobalRequestResult result = new ResourceAdminManager(session).logoutAll(uriInfo.getRequestUri(), realm);
|
||||
|
@ -433,7 +477,7 @@ public class RealmAdminResource {
|
|||
@Path("sessions/{session}")
|
||||
@DELETE
|
||||
public void deleteSession(@PathParam("session") String sessionId) {
|
||||
auth.init(RealmAuth.Resource.USER).requireManage();
|
||||
auth.users().requireManage();
|
||||
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
|
||||
if (userSession == null) throw new NotFoundException("Sesssion not found");
|
||||
|
@ -455,7 +499,7 @@ public class RealmAdminResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Map<String, String>> getClientSessionStats() {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
List<Map<String, String>> data = new LinkedList<Map<String, String>>();
|
||||
for (ClientModel client : realm.getClients()) {
|
||||
|
@ -482,7 +526,7 @@ public class RealmAdminResource {
|
|||
@Path("events/config")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RealmEventsConfigRepresentation getRealmEventsConfig() {
|
||||
auth.init(RealmAuth.Resource.EVENTS).requireView();
|
||||
auth.realm().requireViewEvents();
|
||||
|
||||
RealmEventsConfigRepresentation config = ModelToRepresentation.toEventsConfigReprensetation(realm);
|
||||
if (config.getEnabledEventTypes() == null || config.getEnabledEventTypes().isEmpty()) {
|
||||
|
@ -507,7 +551,7 @@ public class RealmAdminResource {
|
|||
@Path("events/config")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) {
|
||||
auth.init(RealmAuth.Resource.EVENTS).requireManage();
|
||||
auth.realm().requireManageEvents();
|
||||
|
||||
logger.debug("updating realm events config: " + realm.getName());
|
||||
new RealmManager(session).updateRealmEventsConfig(rep, realm);
|
||||
|
@ -536,7 +580,7 @@ public class RealmAdminResource {
|
|||
@QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
|
||||
@QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults) {
|
||||
auth.init(RealmAuth.Resource.EVENTS).requireView();
|
||||
auth.realm().requireViewEvents();
|
||||
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
|
||||
|
@ -629,7 +673,7 @@ public class RealmAdminResource {
|
|||
@QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults,
|
||||
@QueryParam("resourceTypes") List<String> resourceTypes) {
|
||||
auth.init(RealmAuth.Resource.EVENTS).requireView();
|
||||
auth.realm().requireViewEvents();
|
||||
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
AdminEventQuery query = eventStore.createAdminQuery().realm(realm.getId());;
|
||||
|
@ -722,7 +766,7 @@ public class RealmAdminResource {
|
|||
@Path("events")
|
||||
@DELETE
|
||||
public void clearEvents() {
|
||||
auth.init(RealmAuth.Resource.EVENTS).requireManage();
|
||||
auth.realm().requireManageEvents();
|
||||
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
eventStore.clear(realm.getId());
|
||||
|
@ -735,7 +779,7 @@ public class RealmAdminResource {
|
|||
@Path("admin-events")
|
||||
@DELETE
|
||||
public void clearAdminEvents() {
|
||||
auth.init(RealmAuth.Resource.EVENTS).requireManage();
|
||||
auth.realm().requireManageEvents();
|
||||
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
eventStore.clearAdmin(realm.getId());
|
||||
|
@ -757,7 +801,7 @@ public class RealmAdminResource {
|
|||
@QueryParam("bindDn") String bindDn, @QueryParam("bindCredential") String bindCredential,
|
||||
@QueryParam("useTruststoreSpi") String useTruststoreSpi, @QueryParam("connectionTimeout") String connectionTimeout,
|
||||
@QueryParam("componentId") String componentId) {
|
||||
auth.init(RealmAuth.Resource.REALM).requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
if (componentId != null && bindCredential.equals(ComponentRepresentation.SECRET_VALUE)) {
|
||||
bindCredential = realm.getComponent(componentId).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL);
|
||||
|
@ -782,7 +826,7 @@ public class RealmAdminResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("default-groups")
|
||||
public List<GroupRepresentation> getDefaultGroups() {
|
||||
auth.requireView();
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
List<GroupRepresentation> defaults = new LinkedList<>();
|
||||
for (GroupModel group : realm.getDefaultGroups()) {
|
||||
|
@ -794,7 +838,7 @@ public class RealmAdminResource {
|
|||
@NoCache
|
||||
@Path("default-groups/{groupId}")
|
||||
public void addDefaultGroup(@PathParam("groupId") String groupId) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
GroupModel group = realm.getGroupById(groupId);
|
||||
if (group == null) {
|
||||
|
@ -809,7 +853,7 @@ public class RealmAdminResource {
|
|||
@NoCache
|
||||
@Path("default-groups/{groupId}")
|
||||
public void removeDefaultGroup(@PathParam("groupId") String groupId) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
GroupModel group = realm.getGroupById(groupId);
|
||||
if (group == null) {
|
||||
|
@ -834,13 +878,12 @@ public class RealmAdminResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public GroupRepresentation getGroupByPath(@PathParam("path") String path) {
|
||||
auth.requireView();
|
||||
|
||||
GroupModel found = KeycloakModelUtils.findGroupByPath(realm, path);
|
||||
if (found == null) {
|
||||
throw new NotFoundException("Group path does not exist");
|
||||
|
||||
}
|
||||
auth.groups().requireView(found);
|
||||
return ModelToRepresentation.toGroupHierarchy(found, true);
|
||||
}
|
||||
|
||||
|
@ -854,7 +897,7 @@ public class RealmAdminResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response partialImport(PartialImportRepresentation rep) {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
PartialImportManager partialImport = new PartialImportManager(rep, session, realm, adminEvent);
|
||||
return partialImport.saveResources();
|
||||
|
@ -888,7 +931,7 @@ public class RealmAdminResource {
|
|||
@Path("clear-realm-cache")
|
||||
@POST
|
||||
public void clearRealmCache() {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
CacheRealmProvider cache = session.getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
|
@ -905,7 +948,7 @@ public class RealmAdminResource {
|
|||
@Path("clear-user-cache")
|
||||
@POST
|
||||
public void clearUserCache() {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
UserCache cache = session.getProvider(UserCache.class);
|
||||
if (cache != null) {
|
||||
|
@ -922,7 +965,7 @@ public class RealmAdminResource {
|
|||
@Path("clear-keys-cache")
|
||||
@POST
|
||||
public void clearKeysCache() {
|
||||
auth.requireManage();
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
PublicKeyStorageProvider cache = session.getProvider(PublicKeyStorageProvider.class);
|
||||
if (cache != null) {
|
||||
|
|
|
@ -34,6 +34,8 @@ import org.keycloak.services.ErrorResponse;
|
|||
import org.keycloak.services.ForbiddenException;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
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.GET;
|
||||
|
@ -94,18 +96,11 @@ public class RealmsAdminResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<RealmRepresentation> getRealms() {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
|
||||
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||
List<RealmModel> realms = session.realms().getRealms();
|
||||
for (RealmModel realm : realms) {
|
||||
addRealmRep(reps, realm, realm.getMasterAdminClient());
|
||||
}
|
||||
} else {
|
||||
ClientModel adminApp = auth.getRealm().getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm()));
|
||||
addRealmRep(reps, auth.getRealm(), adminApp);
|
||||
List<RealmModel> realms = session.realms().getRealms();
|
||||
for (RealmModel realm : realms) {
|
||||
addRealmRep(reps, realm);
|
||||
}
|
||||
|
||||
if (reps.isEmpty()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
@ -114,10 +109,10 @@ public class RealmsAdminResource {
|
|||
return reps;
|
||||
}
|
||||
|
||||
protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm, ClientModel realmManagementClient) {
|
||||
if (auth.hasAppRole(realmManagementClient, AdminRoles.VIEW_REALM)) {
|
||||
protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm) {
|
||||
if (AdminPermissions.realms(session, auth).canView(realm)) {
|
||||
reps.add(ModelToRepresentation.toRepresentation(realm, false));
|
||||
} else if (auth.hasOneOfAppRole(realmManagementClient, AdminRoles.ALL_REALM_ROLES)) {
|
||||
} else if (AdminPermissions.realms(session, auth).isAdmin(realm)) {
|
||||
RealmRepresentation rep = new RealmRepresentation();
|
||||
rep.setRealm(realm.getName());
|
||||
reps.add(rep);
|
||||
|
@ -138,12 +133,7 @@ public class RealmsAdminResource {
|
|||
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
realmManager.setContextPath(keycloak.getContextPath());
|
||||
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
AdminPermissions.realms(session, auth).requireCreateRealm();
|
||||
|
||||
logger.debugv("importRealm: {0}", rep.getRealm());
|
||||
|
||||
|
@ -191,13 +181,7 @@ public class RealmsAdminResource {
|
|||
&& !auth.getRealm().equals(realm)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
RealmAuth realmAuth;
|
||||
|
||||
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||
realmAuth = new RealmAuth(auth, realm.getMasterAdminClient());
|
||||
} else {
|
||||
realmAuth = new RealmAuth(auth, realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())));
|
||||
}
|
||||
AdminPermissionEvaluator realmAuth = AdminPermissions.evaluator(session, realm, auth);
|
||||
|
||||
AdminEventBuilder adminEvent = new AdminEventBuilder(realm, auth, session, clientConnection);
|
||||
session.getContext().setRealm(realm);
|
||||
|
|
|
@ -19,6 +19,10 @@ package org.keycloak.services.resources.admin;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
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.ResourceType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
|
@ -26,6 +30,7 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -39,7 +44,9 @@ import javax.ws.rs.Produces;
|
|||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -52,7 +59,7 @@ import java.util.Set;
|
|||
public class RoleByIdResource extends RoleResource {
|
||||
protected static final Logger logger = Logger.getLogger(RoleByIdResource.class);
|
||||
private final RealmModel realm;
|
||||
private final RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
||||
@Context
|
||||
|
@ -61,7 +68,7 @@ public class RoleByIdResource extends RoleResource {
|
|||
@Context
|
||||
private UriInfo uriInfo;
|
||||
|
||||
public RoleByIdResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public RoleByIdResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
super(realm);
|
||||
|
||||
this.realm = realm;
|
||||
|
@ -80,9 +87,9 @@ public class RoleByIdResource extends RoleResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RoleRepresentation getRole(final @PathParam("role-id") String id) {
|
||||
auth.requireAny();
|
||||
|
||||
RoleModel roleModel = getRoleModel(id);
|
||||
auth.roles().requireView(roleModel);
|
||||
return getRole(roleModel);
|
||||
}
|
||||
|
||||
|
@ -91,17 +98,7 @@ public class RoleByIdResource extends RoleResource {
|
|||
if (roleModel == null) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,9 +110,8 @@ public class RoleByIdResource extends RoleResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public void deleteRole(final @PathParam("role-id") String id) {
|
||||
auth.requireManage();
|
||||
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireManage(role);
|
||||
deleteRole(role);
|
||||
|
||||
if (role.isClientRole()) {
|
||||
|
@ -137,9 +133,8 @@ public class RoleByIdResource extends RoleResource {
|
|||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void updateRole(final @PathParam("role-id") String id, final RoleRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireManage(role);
|
||||
updateRole(rep, role);
|
||||
|
||||
if (role.isClientRole()) {
|
||||
|
@ -161,10 +156,9 @@ public class RoleByIdResource extends RoleResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void addComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
RoleModel role = getRoleModel(id);
|
||||
addComposites(adminEvent, uriInfo, roles, role);
|
||||
auth.roles().requireManage(role);
|
||||
addComposites(auth, adminEvent, uriInfo, roles, role);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -180,11 +174,10 @@ public class RoleByIdResource extends RoleResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-id") String id) {
|
||||
auth.requireAny();
|
||||
|
||||
if (logger.isDebugEnabled()) logger.debug("*** getRoleComposites: '" + id + "'");
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.requireView();
|
||||
auth.roles().requireView(role);
|
||||
return getRoleComposites(role);
|
||||
}
|
||||
|
||||
|
@ -199,9 +192,9 @@ public class RoleByIdResource extends RoleResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-id") String id) {
|
||||
auth.requireAny();
|
||||
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireView(role);
|
||||
auth.roles().requireView(role);
|
||||
return getRealmRoleComposites(role);
|
||||
}
|
||||
|
||||
|
@ -218,9 +211,9 @@ public class RoleByIdResource extends RoleResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Set<RoleRepresentation> getClientRoleComposites(final @PathParam("role-id") String id,
|
||||
final @PathParam("client") String client) {
|
||||
auth.requireAny();
|
||||
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireView(role);
|
||||
ClientModel clientModel = realm.getClientById(client);
|
||||
if (clientModel == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
|
@ -238,10 +231,64 @@ public class RoleByIdResource extends RoleResource {
|
|||
@DELETE
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void deleteComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireManage(role);
|
||||
deleteComposites(adminEvent, uriInfo, roles, role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object stating whether role Authoirzation permissions have been initialized or not and a reference
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Path("{role-id}/management/permissions")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ManagementPermissionReference getManagementPermissions(final @PathParam("role-id") String id) {
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireView(role);
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
if (!permissions.roles().isPermissionsEnabled(role)) {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
return toMgmtRef(role, permissions);
|
||||
}
|
||||
|
||||
public static ManagementPermissionReference toMgmtRef(RoleModel role, AdminPermissionManagement permissions) {
|
||||
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||
ref.setEnabled(true);
|
||||
ref.setResource(permissions.roles().resource(role).getId());
|
||||
ref.setScopePermissions(permissions.roles().getPermissions(role));
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object stating whether role Authoirzation permissions have been initialized or not and a reference
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* @return initialized manage permissions reference
|
||||
*/
|
||||
@Path("{role-id}/management/permissions")
|
||||
@PUT
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-id") String id, ManagementPermissionReference ref) {
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireManage(role);
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
permissions.roles().setPermissionsEnabled(role, ref.isEnabled());
|
||||
if (ref.isEnabled()) {
|
||||
return toMgmtRef(role, permissions);
|
||||
} else {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,26 +19,33 @@ package org.keycloak.services.resources.admin;
|
|||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
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.ResourceType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
@ -54,18 +61,22 @@ import java.util.Set;
|
|||
*/
|
||||
public class RoleContainerResource extends RoleResource {
|
||||
private final RealmModel realm;
|
||||
private final RealmAuth auth;
|
||||
protected AdminPermissionEvaluator auth;
|
||||
|
||||
protected RoleContainerModel roleContainer;
|
||||
private AdminEventBuilder adminEvent;
|
||||
private UriInfo uriInfo;
|
||||
private KeycloakSession session;
|
||||
|
||||
public RoleContainerResource(UriInfo uriInfo, RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent) {
|
||||
public RoleContainerResource(KeycloakSession session, UriInfo uriInfo, RealmModel realm,
|
||||
AdminPermissionEvaluator auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent) {
|
||||
super(realm);
|
||||
this.uriInfo = uriInfo;
|
||||
this.realm = realm;
|
||||
this.auth = auth;
|
||||
this.roleContainer = roleContainer;
|
||||
this.adminEvent = adminEvent;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,11 +88,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<RoleRepresentation> getRoles() {
|
||||
auth.requireAny();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.roles().requireList(roleContainer);
|
||||
|
||||
Set<RoleModel> roleModels = roleContainer.getRoles();
|
||||
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
|
||||
|
@ -100,11 +107,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response createRole(final RoleRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.roles().requireManage(roleContainer);
|
||||
|
||||
if (rep.getName() == null) {
|
||||
throw new BadRequestException();
|
||||
|
@ -143,11 +146,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RoleRepresentation getRole(final @PathParam("role-name") String roleName) {
|
||||
auth.requireView();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
auth.roles().requireView(roleContainer);
|
||||
|
||||
RoleModel roleModel = roleContainer.getRole(roleName);
|
||||
if (roleModel == null) {
|
||||
|
@ -166,12 +165,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public void deleteRole(final @PathParam("role-name") String roleName) {
|
||||
auth.requireManage();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
|
||||
auth.roles().requireManage(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
|
@ -199,12 +193,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
|
||||
auth.roles().requireManage(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
|
@ -236,17 +225,12 @@ public class RoleContainerResource extends RoleResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
|
||||
auth.roles().requireManage(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
}
|
||||
addComposites(adminEvent, uriInfo, roles, role);
|
||||
addComposites(auth, adminEvent, uriInfo, roles, role);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -260,12 +244,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-name") String roleName) {
|
||||
auth.requireView();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
|
||||
auth.roles().requireView(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
|
@ -284,12 +263,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-name") String roleName) {
|
||||
auth.requireView();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
|
||||
auth.roles().requireView(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
|
@ -311,12 +285,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
public Set<RoleRepresentation> getClientRoleComposites(@Context final UriInfo uriInfo,
|
||||
final @PathParam("role-name") String roleName,
|
||||
final @PathParam("client") String client) {
|
||||
auth.requireView();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
|
||||
auth.roles().requireView(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
|
@ -342,12 +311,8 @@ public class RoleContainerResource extends RoleResource {
|
|||
public void deleteComposites(
|
||||
final @PathParam("role-name") String roleName,
|
||||
List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
if (roleContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
|
||||
auth.roles().requireManage(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
|
@ -355,4 +320,57 @@ public class RoleContainerResource extends RoleResource {
|
|||
deleteComposites(adminEvent, uriInfo, roles, role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object stating whether role Authoirzation permissions have been initialized or not and a reference
|
||||
*
|
||||
*
|
||||
* @param roleName
|
||||
* @return
|
||||
*/
|
||||
@Path("{role-name}/management/permissions")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ManagementPermissionReference getManagementPermissions(final @PathParam("role-name") String roleName) {
|
||||
auth.roles().requireView(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
}
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
if (!permissions.roles().isPermissionsEnabled(role)) {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
return RoleByIdResource.toMgmtRef(role, permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object stating whether role Authoirzation permissions have been initialized or not and a reference
|
||||
*
|
||||
*
|
||||
* @param roleName
|
||||
* @return initialized manage permissions reference
|
||||
*/
|
||||
@Path("{role-name}/management/permissions")
|
||||
@PUT
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-name") String roleName, ManagementPermissionReference ref) {
|
||||
auth.roles().requireManage(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new NotFoundException("Could not find role");
|
||||
}
|
||||
|
||||
if (ref.isEnabled()) {
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
permissions.roles().setPermissionsEnabled(role, ref.isEnabled());
|
||||
return RoleByIdResource.toMgmtRef(role, permissions);
|
||||
} else {
|
||||
return new ManagementPermissionReference();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
|
@ -33,6 +34,7 @@ import org.keycloak.representations.idm.ClientMappingsRepresentation;
|
|||
import org.keycloak.representations.idm.MappingsRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.ForbiddenException;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -55,6 +57,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Base resource for managing users
|
||||
|
@ -64,16 +67,19 @@ import java.util.Set;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RoleMapperResource {
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(RoleMapperResource.class);
|
||||
|
||||
protected RealmModel realm;
|
||||
|
||||
private RealmAuth auth;
|
||||
|
||||
private RoleMapperModel roleMapper;
|
||||
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
||||
protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
|
||||
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
|
||||
private AdminPermissionEvaluator auth;
|
||||
|
||||
@Context
|
||||
protected ClientConnection clientConnection;
|
||||
|
||||
|
@ -86,15 +92,21 @@ public class RoleMapperResource {
|
|||
@Context
|
||||
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.realm = realm;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.REALM_ROLE_MAPPING);
|
||||
this.roleMapper = roleMapper;
|
||||
this.managePermission = manageCheck;
|
||||
this.viewPermission = viewCheck;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get role mappings
|
||||
*
|
||||
|
@ -104,11 +116,7 @@ public class RoleMapperResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public MappingsRepresentation getRoleMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (roleMapper == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
MappingsRepresentation all = new MappingsRepresentation();
|
||||
Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings();
|
||||
|
@ -153,11 +161,7 @@ public class RoleMapperResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getRealmRoleMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (roleMapper == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings();
|
||||
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
||||
|
@ -179,11 +183,7 @@ public class RoleMapperResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getCompositeRealmRoleMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (roleMapper == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
Set<RoleModel> roles = realm.getRoles();
|
||||
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
||||
|
@ -205,14 +205,13 @@ public class RoleMapperResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getAvailableRealmRoleMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (roleMapper == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
Set<RoleModel> available = realm.getRoles();
|
||||
return ClientRoleMappingsResource.getAvailableRoles(roleMapper, available);
|
||||
Set<RoleModel> set = available.stream().filter(r ->
|
||||
canMapRole(r)
|
||||
).collect(Collectors.toSet());
|
||||
return ClientRoleMappingsResource.getAvailableRoles(roleMapper, set);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -224,11 +223,7 @@ public class RoleMapperResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void addRealmRoleMappings(List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
if (roleMapper == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
logger.debugv("** addRealmRoleMappings: {0}", roles);
|
||||
|
||||
|
@ -237,6 +232,7 @@ public class RoleMapperResource {
|
|||
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
||||
throw new NotFoundException("Role not found");
|
||||
}
|
||||
auth.roles().requireMapRole(roleModel);
|
||||
roleMapper.grantRole(roleModel);
|
||||
}
|
||||
|
||||
|
@ -252,11 +248,7 @@ public class RoleMapperResource {
|
|||
@DELETE
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void deleteRealmRoleMappings(List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
if (roleMapper == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
logger.debug("deleteRealmRoleMappings");
|
||||
if (roles == null) {
|
||||
|
@ -264,6 +256,7 @@ public class RoleMapperResource {
|
|||
roles = new LinkedList<>();
|
||||
|
||||
for (RoleModel roleModel : roleModels) {
|
||||
auth.roles().requireMapRole(roleModel);
|
||||
roleMapper.deleteRoleMapping(roleModel);
|
||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
||||
}
|
||||
|
@ -274,11 +267,11 @@ public class RoleMapperResource {
|
|||
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
||||
throw new NotFoundException("Role not found");
|
||||
}
|
||||
|
||||
auth.roles().requireMapRole(roleModel);
|
||||
try {
|
||||
roleMapper.deleteRoleMapping(roleModel);
|
||||
} 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()),
|
||||
Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
@ -290,10 +283,20 @@ public class RoleMapperResource {
|
|||
|
||||
}
|
||||
|
||||
private boolean canMapRole(RoleModel roleModel) {
|
||||
return auth.roles().canMapRole(roleModel);
|
||||
}
|
||||
|
||||
@Path("clients/{client}")
|
||||
public ClientRoleMappingsResource getUserClientRoleMappingsResource(@PathParam("client") String client) {
|
||||
ClientModel clientModel = realm.getClientById(client);
|
||||
return new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper, clientModel, adminEvent);
|
||||
if (clientModel == null) {
|
||||
throw new NotFoundException("Client not found");
|
||||
}
|
||||
ClientRoleMappingsResource resource = new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper,
|
||||
clientModel, adminEvent,
|
||||
managePermission, viewPermission);
|
||||
return resource;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.util.Collections;
|
||||
|
@ -60,12 +61,13 @@ public abstract class RoleResource {
|
|||
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) {
|
||||
RoleModel composite = realm.getRoleById(rep.getId());
|
||||
if (composite == null) {
|
||||
throw new NotFoundException("Could not find composite role");
|
||||
}
|
||||
auth.roles().requireMapComposite(composite);
|
||||
role.addCompositeRole(composite);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.keycloak.models.ScopeContainerModel;
|
|||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
|
@ -49,19 +50,25 @@ import java.util.Set;
|
|||
*/
|
||||
public class ScopeMappedClientResource {
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
protected AdminPermissionEvaluator auth;
|
||||
protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
|
||||
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
|
||||
protected ScopeContainerModel scopeContainer;
|
||||
protected KeycloakSession session;
|
||||
protected ClientModel scopedClient;
|
||||
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.auth = auth;
|
||||
this.scopeContainer = scopeContainer;
|
||||
this.session = session;
|
||||
this.scopedClient = scopedClient;
|
||||
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)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getClientScopeMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
Set<RoleModel> mappings = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer); //scopedClient.getClientScopeMappings(client);
|
||||
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
||||
|
@ -101,14 +104,10 @@ public class ScopeMappedClientResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getAvailableClientScopeMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
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)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getCompositeClientScopeMappings() {
|
||||
auth.requireView();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
viewPermission.require();
|
||||
|
||||
Set<RoleModel> roles = scopedClient.getRoles();
|
||||
return ScopeMappedResource.getComposite(scopeContainer, roles);
|
||||
|
@ -141,11 +136,7 @@ public class ScopeMappedClientResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void addClientScopeMapping(List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
for (RoleRepresentation role : roles) {
|
||||
RoleModel roleModel = scopedClient.getRole(role.getName());
|
||||
|
@ -166,11 +157,7 @@ public class ScopeMappedClientResource {
|
|||
@DELETE
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void deleteClientScopeMapping(List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
managePermission.require();
|
||||
|
||||
if (roles == null) {
|
||||
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.MappingsRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
|
@ -56,17 +57,25 @@ import java.util.Set;
|
|||
*/
|
||||
public class ScopeMappedResource {
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
protected AdminPermissionEvaluator auth;
|
||||
protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
|
||||
protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
|
||||
|
||||
protected ScopeContainerModel scopeContainer;
|
||||
protected KeycloakSession session;
|
||||
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.auth = auth;
|
||||
this.scopeContainer = scopeContainer;
|
||||
this.session = session;
|
||||
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)
|
||||
@NoCache
|
||||
public MappingsRepresentation getScopeMappings() {
|
||||
auth.requireView();
|
||||
viewPermission.require();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
|
@ -126,7 +135,7 @@ public class ScopeMappedResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getRealmScopeMappings() {
|
||||
auth.requireView();
|
||||
viewPermission.require();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
|
@ -150,20 +159,21 @@ public class ScopeMappedResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getAvailableRealmScopeMappings() {
|
||||
auth.requireView();
|
||||
viewPermission.require();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
}
|
||||
|
||||
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>();
|
||||
for (RoleModel roleModel : roles) {
|
||||
if (client.hasScope(roleModel)) continue;
|
||||
if (!auth.roles().canMapClientScope(roleModel)) continue;
|
||||
available.add(ModelToRepresentation.toRepresentation(roleModel));
|
||||
}
|
||||
return available;
|
||||
|
@ -183,7 +193,7 @@ public class ScopeMappedResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<RoleRepresentation> getCompositeRealmScopeMappings() {
|
||||
auth.requireView();
|
||||
viewPermission.require();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
|
@ -210,7 +220,7 @@ public class ScopeMappedResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void addRealmScopeMappings(List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
managePermission.require();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
|
@ -236,7 +246,7 @@ public class ScopeMappedResource {
|
|||
@DELETE
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void deleteRealmScopeMappings(List<RoleRepresentation> roles) {
|
||||
auth.requireManage();
|
||||
managePermission.require();
|
||||
|
||||
if (scopeContainer == null) {
|
||||
throw new NotFoundException("Could not find client");
|
||||
|
@ -268,6 +278,9 @@ public class ScopeMappedResource {
|
|||
@Path("clients/{client}")
|
||||
public ScopeMappedClientResource getClientByIdScopeMappings(@PathParam("client") String 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);
|
||||
}
|
||||
}
|
||||
|
|
795
services/src/main/java/org/keycloak/services/resources/admin/UserResource.java
Executable file
795
services/src/main/java/org/keycloak/services/resources/admin/UserResource.java
Executable file
|
@ -0,0 +1,795 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.BadRequestException;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.authentication.actiontoken.execactions.ExecuteActionsActionToken;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.email.EmailException;
|
||||
import org.keycloak.email.EmailTemplateProvider;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserLoginFailureModel;
|
||||
import org.keycloak.models.UserManager;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.utils.RedirectUtils;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.UserConsentRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.ForbiddenException;
|
||||
import org.keycloak.services.ServicesLogger;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.BruteForceProtector;
|
||||
import org.keycloak.services.managers.UserSessionManager;
|
||||
import org.keycloak.services.resources.AccountService;
|
||||
import org.keycloak.services.resources.LoginActionsService;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.validation.Validation;
|
||||
import org.keycloak.storage.ReadOnlyException;
|
||||
import org.keycloak.utils.ProfileHelper;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.net.URI;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Base resource for managing users
|
||||
*
|
||||
* @resource Users
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UserResource {
|
||||
private static final Logger logger = Logger.getLogger(UserResource.class);
|
||||
|
||||
protected RealmModel realm;
|
||||
|
||||
private AdminPermissionEvaluator auth;
|
||||
|
||||
private AdminEventBuilder adminEvent;
|
||||
private UserModel user;
|
||||
|
||||
@Context
|
||||
protected ClientConnection clientConnection;
|
||||
|
||||
@Context
|
||||
protected UriInfo uriInfo;
|
||||
|
||||
@Context
|
||||
protected KeycloakSession session;
|
||||
|
||||
@Context
|
||||
protected HttpHeaders headers;
|
||||
|
||||
public UserResource(RealmModel realm, UserModel user, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.auth = auth;
|
||||
this.realm = realm;
|
||||
this.user = user;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.USER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user
|
||||
*
|
||||
* @param rep
|
||||
* @return
|
||||
*/
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response updateUser(final UserRepresentation rep) {
|
||||
|
||||
auth.users().requireManage(user);
|
||||
try {
|
||||
Set<String> attrsToRemove;
|
||||
if (rep.getAttributes() != null) {
|
||||
attrsToRemove = new HashSet<>(user.getAttributes().keySet());
|
||||
attrsToRemove.removeAll(rep.getAttributes().keySet());
|
||||
} else {
|
||||
attrsToRemove = Collections.emptySet();
|
||||
}
|
||||
|
||||
if (rep.isEnabled() != null && rep.isEnabled()) {
|
||||
UserLoginFailureModel failureModel = session.sessions().getUserLoginFailure(realm, user.getId());
|
||||
if (failureModel != null) {
|
||||
failureModel.clearFailures();
|
||||
}
|
||||
}
|
||||
|
||||
updateUserFromRep(user, rep, attrsToRemove, realm, session, true);
|
||||
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
||||
|
||||
if (session.getTransactionManager().isActive()) {
|
||||
session.getTransactionManager().commit();
|
||||
}
|
||||
return Response.noContent().build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return ErrorResponse.exists("User exists with same username or email");
|
||||
} catch (ReadOnlyException re) {
|
||||
return ErrorResponse.exists("User is read only!");
|
||||
} catch (ModelException me) {
|
||||
logger.warn("Could not update user!", me);
|
||||
return ErrorResponse.exists("Could not update user!");
|
||||
} catch (ForbiddenException fe) {
|
||||
throw fe;
|
||||
} catch (Exception me) { // JPA
|
||||
logger.warn("Could not update user!", me);// may be committed by JTA which can't
|
||||
return ErrorResponse.exists("Could not update user!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateUserFromRep(UserModel user, UserRepresentation rep, Set<String> attrsToRemove, RealmModel realm, KeycloakSession session, boolean removeMissingRequiredActions) {
|
||||
if (rep.getUsername() != null && realm.isEditUsernameAllowed()) {
|
||||
user.setUsername(rep.getUsername());
|
||||
}
|
||||
if (rep.getEmail() != null) user.setEmail(rep.getEmail());
|
||||
if (rep.getFirstName() != null) user.setFirstName(rep.getFirstName());
|
||||
if (rep.getLastName() != null) user.setLastName(rep.getLastName());
|
||||
|
||||
if (rep.isEnabled() != null) user.setEnabled(rep.isEnabled());
|
||||
if (rep.isEmailVerified() != null) user.setEmailVerified(rep.isEmailVerified());
|
||||
|
||||
List<String> reqActions = rep.getRequiredActions();
|
||||
|
||||
if (reqActions != null) {
|
||||
Set<String> allActions = new HashSet<>();
|
||||
for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class)) {
|
||||
allActions.add(factory.getId());
|
||||
}
|
||||
for (String action : allActions) {
|
||||
if (reqActions.contains(action)) {
|
||||
user.addRequiredAction(action);
|
||||
} else if (removeMissingRequiredActions) {
|
||||
user.removeRequiredAction(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rep.getAttributes() != null) {
|
||||
for (Map.Entry<String, List<String>> attr : rep.getAttributes().entrySet()) {
|
||||
user.setAttribute(attr.getKey(), attr.getValue());
|
||||
}
|
||||
|
||||
for (String attr : attrsToRemove) {
|
||||
user.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get representation of the user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public UserRepresentation getUser() {
|
||||
auth.users().requireView(user);
|
||||
|
||||
UserRepresentation rep = ModelToRepresentation.toRepresentation(session, realm, user);
|
||||
|
||||
if (realm.isIdentityFederationEnabled()) {
|
||||
List<FederatedIdentityRepresentation> reps = getFederatedIdentities(user);
|
||||
rep.setFederatedIdentities(reps);
|
||||
}
|
||||
|
||||
if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
|
||||
rep.setEnabled(false);
|
||||
}
|
||||
rep.setAccess(auth.users().getAccess(user));
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Impersonate the user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("impersonation")
|
||||
@POST
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Map<String, Object> impersonate() {
|
||||
ProfileHelper.requireFeature(Profile.Feature.IMPERSONATION);
|
||||
|
||||
auth.users().requireImpersonate(user);
|
||||
RealmModel authenticatedRealm = auth.adminAuth().getRealm();
|
||||
// if same realm logout before impersonation
|
||||
boolean sameRealm = false;
|
||||
if (authenticatedRealm.getId().equals(realm.getId())) {
|
||||
sameRealm = true;
|
||||
UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, auth.adminAuth().getToken().getSessionState());
|
||||
AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection);
|
||||
AuthenticationManager.expireRememberMeCookie(realm, uriInfo, clientConnection);
|
||||
AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, uriInfo, clientConnection, headers, true);
|
||||
}
|
||||
EventBuilder event = new EventBuilder(realm, session, clientConnection);
|
||||
|
||||
String sessionId = KeycloakModelUtils.generateId();
|
||||
UserSessionModel userSession = session.sessions().createUserSession(sessionId, realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
|
||||
AuthenticationManager.createLoginCookie(session, realm, userSession.getUser(), userSession, uriInfo, clientConnection);
|
||||
URI redirect = AccountService.accountServiceApplicationPage(uriInfo).build(realm.getName());
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("sameRealm", sameRealm);
|
||||
result.put("redirect", redirect.toString());
|
||||
event.event(EventType.IMPERSONATE)
|
||||
.session(userSession)
|
||||
.user(user)
|
||||
.detail(Details.IMPERSONATOR_REALM,authenticatedRealm.getName())
|
||||
.detail(Details.IMPERSONATOR, auth.adminAuth().getUser().getUsername()).success();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get sessions associated with the user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("sessions")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<UserSessionRepresentation> getSessions() {
|
||||
auth.users().requireView(user);
|
||||
List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user);
|
||||
List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
|
||||
for (UserSessionModel session : sessions) {
|
||||
UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
|
||||
reps.add(rep);
|
||||
}
|
||||
return reps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get offline sessions associated with the user and client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("offline-sessions/{clientId}")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<UserSessionRepresentation> getOfflineSessions(final @PathParam("clientId") String clientId) {
|
||||
auth.users().requireView(user);
|
||||
ClientModel client = realm.getClientById(clientId);
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Client not found");
|
||||
}
|
||||
List<UserSessionModel> sessions = new UserSessionManager(session).findOfflineSessions(realm, user);
|
||||
List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
|
||||
for (UserSessionModel session : sessions) {
|
||||
UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
|
||||
|
||||
// Update lastSessionRefresh with the timestamp from clientSession
|
||||
AuthenticatedClientSessionModel clientSession = session.getAuthenticatedClientSessions().get(clientId);
|
||||
|
||||
// Skip if userSession is not for this client
|
||||
if (clientSession == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rep.setLastAccess(clientSession.getTimestamp());
|
||||
|
||||
reps.add(rep);
|
||||
}
|
||||
return reps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get social logins associated with the user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("federated-identity")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<FederatedIdentityRepresentation> getFederatedIdentity() {
|
||||
auth.users().requireView(user);
|
||||
|
||||
return getFederatedIdentities(user);
|
||||
}
|
||||
|
||||
private List<FederatedIdentityRepresentation> getFederatedIdentities(UserModel user) {
|
||||
Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm);
|
||||
List<FederatedIdentityRepresentation> result = new ArrayList<FederatedIdentityRepresentation>();
|
||||
|
||||
for (FederatedIdentityModel identity : identities) {
|
||||
for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
|
||||
if (identityProviderModel.getAlias().equals(identity.getIdentityProvider())) {
|
||||
FederatedIdentityRepresentation rep = ModelToRepresentation.toRepresentation(identity);
|
||||
result.add(rep);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a social login provider to the user
|
||||
*
|
||||
* @param provider Social login provider id
|
||||
* @param rep
|
||||
* @return
|
||||
*/
|
||||
@Path("federated-identity/{provider}")
|
||||
@POST
|
||||
@NoCache
|
||||
public Response addFederatedIdentity(final @PathParam("provider") String provider, FederatedIdentityRepresentation rep) {
|
||||
auth.users().requireManage(user);
|
||||
if (session.users().getFederatedIdentity(user, provider, realm) != null) {
|
||||
return ErrorResponse.exists("User is already linked with provider");
|
||||
}
|
||||
|
||||
FederatedIdentityModel socialLink = new FederatedIdentityModel(provider, rep.getUserId(), rep.getUserName());
|
||||
session.users().addFederatedIdentity(realm, user, socialLink);
|
||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(rep).success();
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a social login provider from user
|
||||
*
|
||||
* @param provider Social login provider id
|
||||
*/
|
||||
@Path("federated-identity/{provider}")
|
||||
@DELETE
|
||||
@NoCache
|
||||
public void removeFederatedIdentity(final @PathParam("provider") String provider) {
|
||||
auth.users().requireManage(user);
|
||||
if (!session.users().removeFederatedIdentity(realm, user, provider)) {
|
||||
throw new NotFoundException("Link not found");
|
||||
}
|
||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get consents granted by the user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("consents")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Map<String, Object>> getConsents() {
|
||||
auth.users().requireView(user);
|
||||
List<Map<String, Object>> result = new LinkedList<>();
|
||||
|
||||
Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
|
||||
|
||||
for (ClientModel client : realm.getClients()) {
|
||||
UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId());
|
||||
boolean hasOfflineToken = offlineClients.contains(client);
|
||||
|
||||
if (consent == null && !hasOfflineToken) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UserConsentRepresentation rep = (consent == null) ? null : ModelToRepresentation.toRepresentation(consent);
|
||||
|
||||
Map<String, Object> currentRep = new HashMap<>();
|
||||
currentRep.put("clientId", client.getClientId());
|
||||
currentRep.put("grantedProtocolMappers", (rep==null ? Collections.emptyMap() : rep.getGrantedProtocolMappers()));
|
||||
currentRep.put("grantedRealmRoles", (rep==null ? Collections.emptyList() : rep.getGrantedRealmRoles()));
|
||||
currentRep.put("grantedClientRoles", (rep==null ? Collections.emptyMap() : rep.getGrantedClientRoles()));
|
||||
currentRep.put("createdDate", (rep==null ? null : rep.getCreatedDate()));
|
||||
currentRep.put("lastUpdatedDate", (rep==null ? null : rep.getLastUpdatedDate()));
|
||||
|
||||
List<Map<String, String>> additionalGrants = new LinkedList<>();
|
||||
if (hasOfflineToken) {
|
||||
Map<String, String> offlineTokens = new HashMap<>();
|
||||
offlineTokens.put("client", client.getId());
|
||||
// TODO: translate
|
||||
offlineTokens.put("key", "Offline Token");
|
||||
additionalGrants.add(offlineTokens);
|
||||
}
|
||||
currentRep.put("additionalGrants", additionalGrants);
|
||||
|
||||
result.add(currentRep);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke consent and offline tokens for particular client from user
|
||||
*
|
||||
* @param clientId Client id
|
||||
*/
|
||||
@Path("consents/{client}")
|
||||
@DELETE
|
||||
@NoCache
|
||||
public void revokeConsent(final @PathParam("client") String clientId) {
|
||||
auth.users().requireManage(user);
|
||||
|
||||
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 revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client);
|
||||
|
||||
if (revokedConsent) {
|
||||
// Logout clientSessions for this user and client
|
||||
AuthenticationManager.backchannelUserFromClient(session, realm, user, client, uriInfo, headers);
|
||||
}
|
||||
|
||||
if (!revokedConsent && !revokedOfflineToken) {
|
||||
throw new NotFoundException("Consent nor offline token not found");
|
||||
}
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all user sessions associated with the user
|
||||
*
|
||||
* Also send notification to all clients that have an admin URL to invalidate the sessions for the particular user.
|
||||
*
|
||||
*/
|
||||
@Path("logout")
|
||||
@POST
|
||||
public void logout() {
|
||||
auth.users().requireManage(user);
|
||||
|
||||
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
|
||||
for (UserSessionModel userSession : userSessions) {
|
||||
AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
|
||||
}
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the user
|
||||
*/
|
||||
@DELETE
|
||||
@NoCache
|
||||
public Response deleteUser() {
|
||||
auth.users().requireManage(user);
|
||||
|
||||
boolean removed = new UserManager(session).removeUser(realm, user);
|
||||
if (removed) {
|
||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||
return Response.noContent().build();
|
||||
} else {
|
||||
return ErrorResponse.error("User couldn't be deleted", Status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@Path("role-mappings")
|
||||
public RoleMapperResource getRoleMappings() {
|
||||
AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.users().requireMapRoles(user);
|
||||
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.users().requireView(user);
|
||||
RoleMapperResource resource = new RoleMapperResource(realm, auth, user, adminEvent, manageCheck, viewCheck);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
return resource;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable all credentials for a user of a specific type
|
||||
*
|
||||
* @param credentialTypes
|
||||
*/
|
||||
@Path("disable-credential-types")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void disableCredentialType(List<String> credentialTypes) {
|
||||
auth.users().requireManage(user);
|
||||
if (credentialTypes == null) return;
|
||||
for (String type : credentialTypes) {
|
||||
session.userCredentialManager().disableCredentialType(realm, user, type);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a temporary password for the user
|
||||
*
|
||||
* User will have to reset the temporary password next time they log in.
|
||||
*
|
||||
* @param pass A Temporary password
|
||||
*/
|
||||
@Path("reset-password")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void resetPassword(CredentialRepresentation pass) {
|
||||
auth.users().requireManage(user);
|
||||
if (pass == null || pass.getValue() == null || !CredentialRepresentation.PASSWORD.equals(pass.getType())) {
|
||||
throw new BadRequestException("No password provided");
|
||||
}
|
||||
if (Validation.isBlank(pass.getValue())) {
|
||||
throw new BadRequestException("Empty password not allowed");
|
||||
}
|
||||
|
||||
UserCredentialModel cred = UserCredentialModel.password(pass.getValue(), true);
|
||||
try {
|
||||
session.userCredentialManager().updateCredential(realm, user, cred);
|
||||
} catch (IllegalStateException ise) {
|
||||
throw new BadRequestException("Resetting to N old passwords is not allowed.");
|
||||
} catch (ReadOnlyException mre) {
|
||||
throw new BadRequestException("Can't reset password as account is read only");
|
||||
} catch (ModelException e) {
|
||||
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()),
|
||||
Status.BAD_REQUEST);
|
||||
}
|
||||
if (pass.isTemporary() != null && pass.isTemporary()) user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove TOTP from the user
|
||||
*
|
||||
*/
|
||||
@Path("remove-totp")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void removeTotp() {
|
||||
auth.users().requireManage(user);
|
||||
|
||||
session.userCredentialManager().disableCredentialType(realm, user, CredentialModel.OTP);
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email to the user with a link they can click to reset their password.
|
||||
* The redirectUri and clientId parameters are optional. The default for the
|
||||
* redirect is the account client.
|
||||
*
|
||||
* This endpoint has been deprecated. Please use the execute-actions-email passing a list with
|
||||
* UPDATE_PASSWORD within it.
|
||||
*
|
||||
* @param redirectUri redirect uri
|
||||
* @param clientId client id
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
@Path("reset-password-email")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response resetPasswordEmail(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri,
|
||||
@QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
|
||||
List<String> actions = new LinkedList<>();
|
||||
actions.add(UserModel.RequiredAction.UPDATE_PASSWORD.name());
|
||||
return executeActionsEmail(redirectUri, clientId, null, actions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a update account email to the user
|
||||
*
|
||||
* An email contains a link the user can click to perform a set of required actions.
|
||||
* The redirectUri and clientId parameters are optional. If no redirect is given, then there will
|
||||
* be no link back to click after actions have completed. Redirect uri must be a valid uri for the
|
||||
* particular clientId.
|
||||
*
|
||||
* @param redirectUri Redirect uri
|
||||
* @param clientId Client id
|
||||
* @param lifespan Number of seconds after which the generated token expires
|
||||
* @param actions required actions the user needs to complete
|
||||
* @return
|
||||
*/
|
||||
@Path("execute-actions-email")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response executeActionsEmail(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri,
|
||||
@QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId,
|
||||
@QueryParam("lifespan") Integer lifespan,
|
||||
List<String> actions) {
|
||||
auth.users().requireManage(user);
|
||||
|
||||
if (user.getEmail() == null) {
|
||||
return ErrorResponse.error("User email missing", Status.BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
throw new WebApplicationException(
|
||||
ErrorResponse.error("User is disabled", Status.BAD_REQUEST));
|
||||
}
|
||||
|
||||
if (redirectUri != null && clientId == null) {
|
||||
throw new WebApplicationException(
|
||||
ErrorResponse.error("Client id missing", Status.BAD_REQUEST));
|
||||
}
|
||||
|
||||
if (clientId == null) {
|
||||
clientId = Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
if (client == null || !client.isEnabled()) {
|
||||
throw new WebApplicationException(
|
||||
ErrorResponse.error(clientId + " not enabled", Status.BAD_REQUEST));
|
||||
}
|
||||
|
||||
String redirect;
|
||||
if (redirectUri != null) {
|
||||
redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client);
|
||||
if (redirect == null) {
|
||||
throw new WebApplicationException(
|
||||
ErrorResponse.error("Invalid redirect uri.", Status.BAD_REQUEST));
|
||||
}
|
||||
}
|
||||
|
||||
if (lifespan == null) {
|
||||
lifespan = realm.getActionTokenGeneratedByAdminLifespan();
|
||||
}
|
||||
int expiration = Time.currentTime() + lifespan;
|
||||
ExecuteActionsActionToken token = new ExecuteActionsActionToken(user.getId(), expiration, actions, redirectUri, clientId);
|
||||
|
||||
try {
|
||||
UriBuilder builder = LoginActionsService.actionTokenProcessor(uriInfo);
|
||||
builder.queryParam("key", token.serialize(session, realm, uriInfo));
|
||||
|
||||
String link = builder.build(realm.getName()).toString();
|
||||
|
||||
this.session.getProvider(EmailTemplateProvider.class)
|
||||
.setRealm(realm)
|
||||
.setUser(user)
|
||||
.sendExecuteActions(link, TimeUnit.SECONDS.toMinutes(lifespan));
|
||||
|
||||
//audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
|
||||
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
|
||||
return Response.ok().build();
|
||||
} catch (EmailException e) {
|
||||
ServicesLogger.LOGGER.failedToSendActionsEmail(e);
|
||||
return ErrorResponse.error("Failed to send execute actions email", Status.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email-verification email to the user
|
||||
*
|
||||
* An email contains a link the user can click to verify their email address.
|
||||
* The redirectUri and clientId parameters are optional. The default for the
|
||||
* redirect is the account client.
|
||||
*
|
||||
* @param redirectUri Redirect uri
|
||||
* @param clientId Client id
|
||||
* @return
|
||||
*/
|
||||
@Path("send-verify-email")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response sendVerifyEmail(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri, @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
|
||||
List<String> actions = new LinkedList<>();
|
||||
actions.add(UserModel.RequiredAction.VERIFY_EMAIL.name());
|
||||
return executeActionsEmail(redirectUri, clientId, null, actions);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("groups")
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<GroupRepresentation> groupMembership() {
|
||||
auth.users().requireView(user);
|
||||
List<GroupRepresentation> memberships = new LinkedList<>();
|
||||
for (GroupModel group : user.getGroups()) {
|
||||
memberships.add(ModelToRepresentation.toRepresentation(group, false));
|
||||
}
|
||||
return memberships;
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("groups/{groupId}")
|
||||
@NoCache
|
||||
public void removeMembership(@PathParam("groupId") String groupId) {
|
||||
auth.users().requireManageGroupMembership(user);
|
||||
|
||||
GroupModel group = session.realms().getGroupById(groupId, realm);
|
||||
if (group == null) {
|
||||
throw new NotFoundException("Group not found");
|
||||
}
|
||||
auth.groups().requireManageMembership(group);
|
||||
|
||||
try {
|
||||
if (user.isMemberOf(group)){
|
||||
user.leaveGroup(group);
|
||||
adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
|
||||
}
|
||||
} catch (ModelException me) {
|
||||
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()),
|
||||
Status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("groups/{groupId}")
|
||||
@NoCache
|
||||
public void joinGroup(@PathParam("groupId") String groupId) {
|
||||
auth.users().requireManageGroupMembership(user);
|
||||
GroupModel group = session.realms().getGroupById(groupId, realm);
|
||||
if (group == null) {
|
||||
throw new NotFoundException("Group not found");
|
||||
}
|
||||
auth.groups().requireManageMembership(group);
|
||||
if (!user.isMemberOf(group)){
|
||||
user.joinGroup(group);
|
||||
adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.services.ServicesLogger;
|
||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProvider;
|
||||
|
@ -55,7 +56,7 @@ public class UserStorageProviderResource {
|
|||
|
||||
protected RealmModel realm;
|
||||
|
||||
protected RealmAuth auth;
|
||||
protected AdminPermissionEvaluator auth;
|
||||
|
||||
protected AdminEventBuilder adminEvent;
|
||||
|
||||
|
@ -71,12 +72,10 @@ public class UserStorageProviderResource {
|
|||
@Context
|
||||
protected HttpHeaders headers;
|
||||
|
||||
public UserStorageProviderResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public UserStorageProviderResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.auth = auth;
|
||||
this.realm = realm;
|
||||
this.adminEvent = adminEvent;
|
||||
|
||||
auth.init(RealmAuth.Resource.USER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,7 +93,7 @@ public class UserStorageProviderResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public SynchronizationResult syncUsers(@PathParam("id") String id,
|
||||
@QueryParam("action") String action) {
|
||||
auth.requireManage();
|
||||
auth.users().requireManage();
|
||||
|
||||
ComponentModel model = realm.getComponent(id);
|
||||
if (model == null) {
|
||||
|
@ -139,7 +138,7 @@ public class UserStorageProviderResource {
|
|||
@Path("{id}/remove-imported-users")
|
||||
@NoCache
|
||||
public void removeImportedUsers(@PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
auth.users().requireManage();
|
||||
|
||||
ComponentModel model = realm.getComponent(id);
|
||||
if (model == null) {
|
||||
|
@ -162,7 +161,7 @@ public class UserStorageProviderResource {
|
|||
@Path("{id}/unlink-users")
|
||||
@NoCache
|
||||
public void unlinkUsers(@PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
auth.users().requireManage();
|
||||
|
||||
ComponentModel model = realm.getComponent(id);
|
||||
if (model == null) {
|
||||
|
@ -187,7 +186,7 @@ public class UserStorageProviderResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
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);
|
||||
if (parentModel == null) throw new NotFoundException("Parent model not found");
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.jboss.resteasy.spi.NotFoundException;
|
|||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.authentication.actiontoken.execactions.ExecuteActionsActionToken;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.util.Time;
|
||||
|
@ -34,6 +35,20 @@ import org.keycloak.events.EventBuilder;
|
|||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserLoginFailureModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.*;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
|
@ -67,18 +82,26 @@ import javax.ws.rs.Path;
|
|||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.net.URI;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.*;
|
||||
|
||||
/**
|
||||
* Base resource for managing users
|
||||
|
@ -92,7 +115,7 @@ public class UsersResource {
|
|||
|
||||
protected RealmModel realm;
|
||||
|
||||
private RealmAuth auth;
|
||||
private AdminPermissionEvaluator auth;
|
||||
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
||||
|
@ -108,66 +131,10 @@ public class UsersResource {
|
|||
@Context
|
||||
protected HttpHeaders headers;
|
||||
|
||||
public UsersResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public UsersResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
|
||||
this.auth = auth;
|
||||
this.realm = realm;
|
||||
this.adminEvent = adminEvent.resource(ResourceType.USER);
|
||||
|
||||
auth.init(RealmAuth.Resource.USER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user
|
||||
*
|
||||
* @param id User id
|
||||
* @param rep
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response updateUser(final @PathParam("id") String id, final UserRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
try {
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
Set<String> attrsToRemove;
|
||||
if (rep.getAttributes() != null) {
|
||||
attrsToRemove = new HashSet<>(user.getAttributes().keySet());
|
||||
attrsToRemove.removeAll(rep.getAttributes().keySet());
|
||||
} else {
|
||||
attrsToRemove = Collections.emptySet();
|
||||
}
|
||||
|
||||
if (rep.isEnabled() != null && rep.isEnabled()) {
|
||||
UserLoginFailureModel failureModel = session.sessions().getUserLoginFailure(realm, id);
|
||||
if (failureModel != null) {
|
||||
failureModel.clearFailures();
|
||||
}
|
||||
}
|
||||
|
||||
updateUserFromRep(user, rep, attrsToRemove, realm, session, true);
|
||||
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
||||
|
||||
if (session.getTransactionManager().isActive()) {
|
||||
session.getTransactionManager().commit();
|
||||
}
|
||||
return Response.noContent().build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return ErrorResponse.exists("User exists with same username or email");
|
||||
} catch (ReadOnlyException re) {
|
||||
return ErrorResponse.exists("User is read only!");
|
||||
} catch (ModelException me) {
|
||||
logger.warn("Could not update user!", me);
|
||||
return ErrorResponse.exists("Could not update user!");
|
||||
} catch (Exception me) { // JPA
|
||||
logger.warn("Could not update user!", me);// may be committed by JTA which can't
|
||||
return ErrorResponse.exists("Could not update user!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,7 +149,7 @@ public class UsersResource {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
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
|
||||
if (session.users().getUserByUsername(rep.getUsername(), realm) != null) {
|
||||
|
@ -195,7 +162,7 @@ public class UsersResource {
|
|||
try {
|
||||
UserModel user = session.users().addUser(realm, rep.getUsername());
|
||||
Set<String> emptySet = Collections.emptySet();
|
||||
updateUserFromRep(user, rep, emptySet, realm, session, false);
|
||||
UserResource.updateUserFromRep(user, rep, emptySet, realm, session, false);
|
||||
|
||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, user.getId()).representation(rep).success();
|
||||
|
||||
|
@ -217,45 +184,6 @@ public class UsersResource {
|
|||
return ErrorResponse.exists("Could not create user");
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateUserFromRep(UserModel user, UserRepresentation rep, Set<String> attrsToRemove, RealmModel realm, KeycloakSession session, boolean removeMissingRequiredActions) {
|
||||
if (rep.getUsername() != null && realm.isEditUsernameAllowed()) {
|
||||
user.setUsername(rep.getUsername());
|
||||
}
|
||||
if (rep.getEmail() != null) user.setEmail(rep.getEmail());
|
||||
if (rep.getFirstName() != null) user.setFirstName(rep.getFirstName());
|
||||
if (rep.getLastName() != null) user.setLastName(rep.getLastName());
|
||||
|
||||
if (rep.isEnabled() != null) user.setEnabled(rep.isEnabled());
|
||||
if (rep.isEmailVerified() != null) user.setEmailVerified(rep.isEmailVerified());
|
||||
|
||||
List<String> reqActions = rep.getRequiredActions();
|
||||
|
||||
if (reqActions != null) {
|
||||
Set<String> allActions = new HashSet<>();
|
||||
for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class)) {
|
||||
allActions.add(factory.getId());
|
||||
}
|
||||
for (String action : allActions) {
|
||||
if (reqActions.contains(action)) {
|
||||
user.addRequiredAction(action);
|
||||
} else if (removeMissingRequiredActions) {
|
||||
user.removeRequiredAction(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rep.getAttributes() != null) {
|
||||
for (Map.Entry<String, List<String>> attr : rep.getAttributes().entrySet()) {
|
||||
user.setAttribute(attr.getKey(), attr.getValue());
|
||||
}
|
||||
|
||||
for (String attr : attrsToRemove) {
|
||||
user.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get representation of the user
|
||||
*
|
||||
|
@ -263,368 +191,17 @@ public class UsersResource {
|
|||
* @return
|
||||
*/
|
||||
@Path("{id}")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public UserRepresentation getUser(final @PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
|
||||
public UserResource user(final @PathParam("id") String id) {
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
UserRepresentation rep = ModelToRepresentation.toRepresentation(session, realm, user);
|
||||
|
||||
if (realm.isIdentityFederationEnabled()) {
|
||||
List<FederatedIdentityRepresentation> reps = getFederatedIdentities(user);
|
||||
rep.setFederatedIdentities(reps);
|
||||
}
|
||||
|
||||
if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
|
||||
rep.setEnabled(false);
|
||||
}
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Impersonate the user
|
||||
*
|
||||
* @param id User id
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}/impersonation")
|
||||
@POST
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Map<String, Object> impersonate(final @PathParam("id") String id) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.IMPERSONATION);
|
||||
|
||||
auth.init(RealmAuth.Resource.IMPERSONATION);
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
RealmModel authenticatedRealm = auth.getAuth().getRealm();
|
||||
// if same realm logout before impersonation
|
||||
boolean sameRealm = false;
|
||||
if (authenticatedRealm.getId().equals(realm.getId())) {
|
||||
sameRealm = true;
|
||||
UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, auth.getAuth().getToken().getSessionState());
|
||||
AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection);
|
||||
AuthenticationManager.expireRememberMeCookie(realm, uriInfo, clientConnection);
|
||||
AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, uriInfo, clientConnection, headers, true);
|
||||
}
|
||||
EventBuilder event = new EventBuilder(realm, session, clientConnection);
|
||||
|
||||
String sessionId = KeycloakModelUtils.generateId();
|
||||
UserSessionModel userSession = session.sessions().createUserSession(sessionId, realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
|
||||
AuthenticationManager.createLoginCookie(session, realm, userSession.getUser(), userSession, uriInfo, clientConnection);
|
||||
URI redirect = AccountService.accountServiceApplicationPage(uriInfo).build(realm.getName());
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("sameRealm", sameRealm);
|
||||
result.put("redirect", redirect.toString());
|
||||
event.event(EventType.IMPERSONATE)
|
||||
.session(userSession)
|
||||
.user(user)
|
||||
.detail(Details.IMPERSONATOR_REALM,authenticatedRealm.getName())
|
||||
.detail(Details.IMPERSONATOR, auth.getAuth().getUser().getUsername()).success();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get sessions associated with the user
|
||||
*
|
||||
* @param id User id
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}/sessions")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<UserSessionRepresentation> getSessions(final @PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user);
|
||||
List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
|
||||
for (UserSessionModel session : sessions) {
|
||||
UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
|
||||
reps.add(rep);
|
||||
}
|
||||
return reps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get offline sessions associated with the user and client
|
||||
*
|
||||
* @param id User id
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}/offline-sessions/{clientId}")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<UserSessionRepresentation> getOfflineSessions(final @PathParam("id") String id, final @PathParam("clientId") String clientId) {
|
||||
auth.requireView();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
ClientModel client = realm.getClientById(clientId);
|
||||
if (client == null) {
|
||||
throw new NotFoundException("Client not found");
|
||||
}
|
||||
List<UserSessionModel> sessions = new UserSessionManager(session).findOfflineSessions(realm, user);
|
||||
List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
|
||||
for (UserSessionModel session : sessions) {
|
||||
UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
|
||||
|
||||
// Update lastSessionRefresh with the timestamp from clientSession
|
||||
AuthenticatedClientSessionModel clientSession = session.getAuthenticatedClientSessions().get(clientId);
|
||||
|
||||
// Skip if userSession is not for this client
|
||||
if (clientSession == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rep.setLastAccess(clientSession.getTimestamp());
|
||||
|
||||
reps.add(rep);
|
||||
}
|
||||
return reps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get social logins associated with the user
|
||||
*
|
||||
* @param id User id
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}/federated-identity")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<FederatedIdentityRepresentation> getFederatedIdentity(final @PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
return getFederatedIdentities(user);
|
||||
}
|
||||
|
||||
private List<FederatedIdentityRepresentation> getFederatedIdentities(UserModel user) {
|
||||
Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm);
|
||||
List<FederatedIdentityRepresentation> result = new ArrayList<FederatedIdentityRepresentation>();
|
||||
|
||||
for (FederatedIdentityModel identity : identities) {
|
||||
for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
|
||||
if (identityProviderModel.getAlias().equals(identity.getIdentityProvider())) {
|
||||
FederatedIdentityRepresentation rep = ModelToRepresentation.toRepresentation(identity);
|
||||
result.add(rep);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a social login provider to the user
|
||||
*
|
||||
* @param id User id
|
||||
* @param provider Social login provider id
|
||||
* @param rep
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}/federated-identity/{provider}")
|
||||
@POST
|
||||
@NoCache
|
||||
public Response addFederatedIdentity(final @PathParam("id") String id, final @PathParam("provider") String provider, FederatedIdentityRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
if (session.users().getFederatedIdentity(user, provider, realm) != null) {
|
||||
return ErrorResponse.exists("User is already linked with provider");
|
||||
}
|
||||
|
||||
FederatedIdentityModel socialLink = new FederatedIdentityModel(provider, rep.getUserId(), rep.getUserName());
|
||||
session.users().addFederatedIdentity(realm, user, socialLink);
|
||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(rep).success();
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a social login provider from user
|
||||
*
|
||||
* @param id User id
|
||||
* @param provider Social login provider id
|
||||
*/
|
||||
@Path("{id}/federated-identity/{provider}")
|
||||
@DELETE
|
||||
@NoCache
|
||||
public void removeFederatedIdentity(final @PathParam("id") String id, final @PathParam("provider") String provider) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
if (!session.users().removeFederatedIdentity(realm, user, provider)) {
|
||||
throw new NotFoundException("Link not found");
|
||||
}
|
||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get consents granted by the user
|
||||
*
|
||||
* @param id User id
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}/consents")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Map<String, Object>> getConsents(final @PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
List<Map<String, Object>> result = new LinkedList<>();
|
||||
|
||||
Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
|
||||
|
||||
for (ClientModel client : realm.getClients()) {
|
||||
UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId());
|
||||
boolean hasOfflineToken = offlineClients.contains(client);
|
||||
|
||||
if (consent == null && !hasOfflineToken) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UserConsentRepresentation rep = (consent == null) ? null : ModelToRepresentation.toRepresentation(consent);
|
||||
|
||||
Map<String, Object> currentRep = new HashMap<>();
|
||||
currentRep.put("clientId", client.getClientId());
|
||||
currentRep.put("grantedProtocolMappers", (rep==null ? Collections.emptyMap() : rep.getGrantedProtocolMappers()));
|
||||
currentRep.put("grantedRealmRoles", (rep==null ? Collections.emptyList() : rep.getGrantedRealmRoles()));
|
||||
currentRep.put("grantedClientRoles", (rep==null ? Collections.emptyMap() : rep.getGrantedClientRoles()));
|
||||
currentRep.put("createdDate", (rep==null ? null : rep.getCreatedDate()));
|
||||
currentRep.put("lastUpdatedDate", (rep==null ? null : rep.getLastUpdatedDate()));
|
||||
|
||||
List<Map<String, String>> additionalGrants = new LinkedList<>();
|
||||
if (hasOfflineToken) {
|
||||
Map<String, String> offlineTokens = new HashMap<>();
|
||||
offlineTokens.put("client", client.getId());
|
||||
// TODO: translate
|
||||
offlineTokens.put("key", "Offline Token");
|
||||
additionalGrants.add(offlineTokens);
|
||||
}
|
||||
currentRep.put("additionalGrants", additionalGrants);
|
||||
|
||||
result.add(currentRep);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke consent and offline tokens for particular client from user
|
||||
*
|
||||
* @param id User id
|
||||
* @param clientId Client id
|
||||
*/
|
||||
@Path("{id}/consents/{client}")
|
||||
@DELETE
|
||||
@NoCache
|
||||
public void revokeConsent(final @PathParam("id") String id, final @PathParam("client") String clientId) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
boolean revokedConsent = session.users().revokeConsentForClient(realm, user.getId(), client.getId());
|
||||
boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client);
|
||||
|
||||
if (revokedConsent) {
|
||||
// Logout clientSessions for this user and client
|
||||
AuthenticationManager.backchannelUserFromClient(session, realm, user, client, uriInfo, headers);
|
||||
}
|
||||
|
||||
if (!revokedConsent && !revokedOfflineToken) {
|
||||
throw new NotFoundException("Consent nor offline token not found");
|
||||
}
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all user sessions associated with the user
|
||||
*
|
||||
* Also send notification to all clients that have an admin URL to invalidate the sessions for the particular user.
|
||||
*
|
||||
* @param id User id
|
||||
*/
|
||||
@Path("{id}/logout")
|
||||
@POST
|
||||
public void logout(final @PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
|
||||
for (UserSessionModel userSession : userSessions) {
|
||||
AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
|
||||
}
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the user
|
||||
*
|
||||
* @param id User id
|
||||
*/
|
||||
@Path("{id}")
|
||||
@DELETE
|
||||
@NoCache
|
||||
public Response deleteUser(final @PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
boolean removed = new UserManager(session).removeUser(realm, user);
|
||||
if (removed) {
|
||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||
return Response.noContent().build();
|
||||
} else {
|
||||
return ErrorResponse.error("User couldn't be deleted", Response.Status.BAD_REQUEST);
|
||||
// we do this to make sure somebody can't phish ids
|
||||
if (auth.users().canQuery()) throw new NotFoundException("User not found");
|
||||
else throw new ForbiddenException();
|
||||
}
|
||||
UserResource resource = new UserResource(realm, user, auth, adminEvent);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
//resourceContext.initResource(users);
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -651,7 +228,7 @@ public class UsersResource {
|
|||
@QueryParam("username") String username,
|
||||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults) {
|
||||
auth.requireView();
|
||||
auth.users().requireQuery();
|
||||
|
||||
firstResult = firstResult != null ? firstResult : -1;
|
||||
maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
|
||||
|
@ -679,8 +256,12 @@ public class UsersResource {
|
|||
userModels = session.users().getUsers(realm, firstResult, maxResults, false);
|
||||
}
|
||||
|
||||
boolean canViewGlobal = auth.users().canView();
|
||||
for (UserModel user : userModels) {
|
||||
results.add(ModelToRepresentation.toRepresentation(session, realm, user));
|
||||
if (!canViewGlobal && !auth.users().canView(user)) continue;
|
||||
UserRepresentation userRep = ModelToRepresentation.toRepresentation(session, realm, user);
|
||||
userRep.setAccess(auth.users().getAccess(user));
|
||||
results.add(userRep);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
@ -690,311 +271,8 @@ public class UsersResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Integer getUsersCount() {
|
||||
auth.requireView();
|
||||
auth.users().requireView();
|
||||
|
||||
return session.users().getUsersCount(realm);
|
||||
}
|
||||
|
||||
@Path("{id}/role-mappings")
|
||||
public RoleMapperResource getRoleMappings(@PathParam("id") String id) {
|
||||
auth.init(RealmAuth.Resource.USER);
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
|
||||
RoleMapperResource resource = new RoleMapperResource(realm, auth, user, adminEvent);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
return resource;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable all credentials for a user of a specific type
|
||||
*
|
||||
* @param id
|
||||
* @param credentialTypes
|
||||
*/
|
||||
@Path("{id}/disable-credential-types")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void disableCredentialType(@PathParam("id") String id, List<String> credentialTypes) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
if (credentialTypes == null) return;
|
||||
for (String type : credentialTypes) {
|
||||
session.userCredentialManager().disableCredentialType(realm, user, type);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a temporary password for the user
|
||||
*
|
||||
* User will have to reset the temporary password next time they log in.
|
||||
*
|
||||
* @param id User id
|
||||
* @param pass A Temporary password
|
||||
*/
|
||||
@Path("{id}/reset-password")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void resetPassword(@PathParam("id") String id, CredentialRepresentation pass) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
if (pass == null || pass.getValue() == null || !CredentialRepresentation.PASSWORD.equals(pass.getType())) {
|
||||
throw new BadRequestException("No password provided");
|
||||
}
|
||||
if (Validation.isBlank(pass.getValue())) {
|
||||
throw new BadRequestException("Empty password not allowed");
|
||||
}
|
||||
|
||||
UserCredentialModel cred = UserCredentialModel.password(pass.getValue(), true);
|
||||
try {
|
||||
session.userCredentialManager().updateCredential(realm, user, cred);
|
||||
} catch (IllegalStateException ise) {
|
||||
throw new BadRequestException("Resetting to N old passwords is not allowed.");
|
||||
} catch (ReadOnlyException mre) {
|
||||
throw new BadRequestException("Can't reset password as account is read only");
|
||||
} catch (ModelException e) {
|
||||
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
|
||||
throw new ErrorResponseException(e.getMessage(), MessageFormat.format(messages.getProperty(e.getMessage(), e.getMessage()), e.getParameters()),
|
||||
Status.BAD_REQUEST);
|
||||
}
|
||||
if (pass.isTemporary() != null && pass.isTemporary()) user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove TOTP from the user
|
||||
*
|
||||
* @param id User id
|
||||
*/
|
||||
@Path("{id}/remove-totp")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void removeTotp(@PathParam("id") String id) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
session.userCredentialManager().disableCredentialType(realm, user, CredentialModel.OTP);
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email to the user with a link they can click to reset their password.
|
||||
* The redirectUri and clientId parameters are optional. The default for the
|
||||
* redirect is the account client.
|
||||
*
|
||||
* This endpoint has been deprecated. Please use the execute-actions-email passing a list with
|
||||
* UPDATE_PASSWORD within it.
|
||||
*
|
||||
* @param id
|
||||
* @param redirectUri redirect uri
|
||||
* @param clientId client id
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
@Path("{id}/reset-password-email")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response resetPasswordEmail(@PathParam("id") String id,
|
||||
@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri,
|
||||
@QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
|
||||
List<String> actions = new LinkedList<>();
|
||||
actions.add(UserModel.RequiredAction.UPDATE_PASSWORD.name());
|
||||
return executeActionsEmail(id, redirectUri, clientId, null, actions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a update account email to the user
|
||||
*
|
||||
* An email contains a link the user can click to perform a set of required actions.
|
||||
* The redirectUri and clientId parameters are optional. If no redirect is given, then there will
|
||||
* be no link back to click after actions have completed. Redirect uri must be a valid uri for the
|
||||
* particular clientId.
|
||||
*
|
||||
* @param id User is
|
||||
* @param redirectUri Redirect uri
|
||||
* @param clientId Client id
|
||||
* @param lifespan Number of seconds after which the generated token expires
|
||||
* @param actions required actions the user needs to complete
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}/execute-actions-email")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response executeActionsEmail(@PathParam("id") String id,
|
||||
@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri,
|
||||
@QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId,
|
||||
@QueryParam("lifespan") Integer lifespan,
|
||||
List<String> actions) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
return ErrorResponse.error("User not found", Response.Status.NOT_FOUND);
|
||||
}
|
||||
|
||||
if (user.getEmail() == null) {
|
||||
return ErrorResponse.error("User email missing", Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
throw new WebApplicationException(
|
||||
ErrorResponse.error("User is disabled", Response.Status.BAD_REQUEST));
|
||||
}
|
||||
|
||||
if (redirectUri != null && clientId == null) {
|
||||
throw new WebApplicationException(
|
||||
ErrorResponse.error("Client id missing", Response.Status.BAD_REQUEST));
|
||||
}
|
||||
|
||||
if (clientId == null) {
|
||||
clientId = Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
if (client == null || !client.isEnabled()) {
|
||||
throw new WebApplicationException(
|
||||
ErrorResponse.error(clientId + " not enabled", Response.Status.BAD_REQUEST));
|
||||
}
|
||||
|
||||
String redirect;
|
||||
if (redirectUri != null) {
|
||||
redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client);
|
||||
if (redirect == null) {
|
||||
throw new WebApplicationException(
|
||||
ErrorResponse.error("Invalid redirect uri.", Response.Status.BAD_REQUEST));
|
||||
}
|
||||
}
|
||||
|
||||
if (lifespan == null) {
|
||||
lifespan = realm.getActionTokenGeneratedByAdminLifespan();
|
||||
}
|
||||
int expiration = Time.currentTime() + lifespan;
|
||||
ExecuteActionsActionToken token = new ExecuteActionsActionToken(id, expiration, actions, redirectUri, clientId);
|
||||
|
||||
try {
|
||||
UriBuilder builder = LoginActionsService.actionTokenProcessor(uriInfo);
|
||||
builder.queryParam("key", token.serialize(session, realm, uriInfo));
|
||||
|
||||
String link = builder.build(realm.getName()).toString();
|
||||
|
||||
this.session.getProvider(EmailTemplateProvider.class)
|
||||
.setRealm(realm)
|
||||
.setUser(user)
|
||||
.sendExecuteActions(link, TimeUnit.SECONDS.toMinutes(lifespan));
|
||||
|
||||
//audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
|
||||
|
||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||
|
||||
return Response.ok().build();
|
||||
} catch (EmailException e) {
|
||||
ServicesLogger.LOGGER.failedToSendActionsEmail(e);
|
||||
return ErrorResponse.error("Failed to send execute actions email", Response.Status.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email-verification email to the user
|
||||
*
|
||||
* An email contains a link the user can click to verify their email address.
|
||||
* The redirectUri and clientId parameters are optional. The default for the
|
||||
* redirect is the account client.
|
||||
*
|
||||
* @param id User id
|
||||
* @param redirectUri Redirect uri
|
||||
* @param clientId Client id
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}/send-verify-email")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response sendVerifyEmail(@PathParam("id") String id, @QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri, @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
|
||||
List<String> actions = new LinkedList<>();
|
||||
actions.add(UserModel.RequiredAction.VERIFY_EMAIL.name());
|
||||
return executeActionsEmail(id, redirectUri, clientId, null, actions);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{id}/groups")
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<GroupRepresentation> groupMembership(@PathParam("id") String id) {
|
||||
auth.requireView();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
List<GroupRepresentation> memberships = new LinkedList<>();
|
||||
for (GroupModel group : user.getGroups()) {
|
||||
memberships.add(ModelToRepresentation.toRepresentation(group, false));
|
||||
}
|
||||
return memberships;
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}/groups/{groupId}")
|
||||
@NoCache
|
||||
public void removeMembership(@PathParam("id") String id, @PathParam("groupId") String groupId) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
GroupModel group = session.realms().getGroupById(groupId, realm);
|
||||
if (group == null) {
|
||||
throw new NotFoundException("Group not found");
|
||||
}
|
||||
|
||||
try {
|
||||
if (user.isMemberOf(group)){
|
||||
user.leaveGroup(group);
|
||||
adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
|
||||
}
|
||||
} catch (ModelException me) {
|
||||
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
|
||||
throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),
|
||||
Response.Status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{id}/groups/{groupId}")
|
||||
@NoCache
|
||||
public void joinGroup(@PathParam("id") String id, @PathParam("groupId") String groupId) {
|
||||
auth.requireManage();
|
||||
|
||||
UserModel user = session.users().getUserById(id, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
GroupModel group = session.realms().getGroupById(groupId, realm);
|
||||
if (group == null) {
|
||||
throw new NotFoundException("Group not found");
|
||||
}
|
||||
if (!user.isMemberOf(group)){
|
||||
user.joinGroup(group);
|
||||
adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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();
|
||||
|
||||
void requireAnyAdminRole();
|
||||
|
||||
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,38 @@
|
|||
/*
|
||||
* 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.AuthorizationProvider;
|
||||
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";
|
||||
|
||||
AuthorizationProvider authz();
|
||||
|
||||
RolePermissionManagement roles();
|
||||
UserPermissionManagement users();
|
||||
GroupPermissionManagement groups();
|
||||
ClientPermissionManagement clients();
|
||||
|
||||
ResourceServer realmResourceServer();
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
import org.keycloak.provider.ProviderEventListener;
|
||||
import org.keycloak.provider.ProviderEventManager;
|
||||
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 RealmsPermissionEvaluator realms(KeycloakSession session, AdminAuth auth) {
|
||||
return new MgmtPermissions(session, auth);
|
||||
}
|
||||
|
||||
public static AdminPermissionManagement management(KeycloakSession session, RealmModel realm) {
|
||||
return new MgmtPermissions(session, realm);
|
||||
}
|
||||
|
||||
public static void registerListener(ProviderEventManager manager) {
|
||||
manager.register(new ProviderEventListener() {
|
||||
@Override
|
||||
public void onEvent(ProviderEvent event) {
|
||||
if (event instanceof RoleContainerModel.RoleRemovedEvent) {
|
||||
RoleContainerModel.RoleRemovedEvent cast = (RoleContainerModel.RoleRemovedEvent)event;
|
||||
RoleModel role = cast.getRole();
|
||||
RealmModel realm;
|
||||
if (role.getContainer() instanceof ClientModel) {
|
||||
realm = ((ClientModel)role.getContainer()).getRealm();
|
||||
|
||||
} else {
|
||||
realm = (RealmModel)role.getContainer();
|
||||
}
|
||||
management(cast.getKeycloakSession(), realm).roles().setPermissionsEnabled(role, false);
|
||||
} else if (event instanceof RealmModel.ClientRemovedEvent) {
|
||||
RealmModel.ClientRemovedEvent cast = (RealmModel.ClientRemovedEvent)event;
|
||||
management(cast.getKeycloakSession(), cast.getClient().getRealm()).clients().setPermissionsEnabled(cast.getClient(), false);
|
||||
} else if (event instanceof GroupModel.GroupRemovedEvent) {
|
||||
GroupModel.GroupRemovedEvent cast = (GroupModel.GroupRemovedEvent)event;
|
||||
management(cast.getKeycloakSession(), cast.getRealm()).groups().setPermissionsEnabled(cast.getGroup(), false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
void requireListTemplates();
|
||||
|
||||
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);
|
||||
|
||||
boolean canConfigure(ClientModel client);
|
||||
|
||||
void requireConfigure(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);
|
||||
|
||||
boolean canMapRoles(ClientModel client);
|
||||
|
||||
boolean canMapCompositeRoles(ClientModel client);
|
||||
|
||||
boolean canMapClientScopeRoles(ClientModel client);
|
||||
|
||||
Map<String, Boolean> getAccess(ClientModel client);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.ClientModel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface ClientPermissionManagement {
|
||||
public static final String MAP_ROLES_SCOPE = "map-roles";
|
||||
public static final String MAP_ROLES_CLIENT_SCOPE = "map-roles-client-scope";
|
||||
public static final String MAP_ROLES_COMPOSITE_SCOPE = "map-roles-composite";
|
||||
public static final String CONFIGURE_SCOPE = "configure";
|
||||
|
||||
boolean isPermissionsEnabled(ClientModel client);
|
||||
|
||||
void setPermissionsEnabled(ClientModel client, boolean enable);
|
||||
|
||||
Resource resource(ClientModel client);
|
||||
|
||||
Map<String, String> getPermissions(ClientModel client);
|
||||
|
||||
Policy mapRolesPermission(ClientModel client);
|
||||
|
||||
Policy mapRolesClientScopePermission(ClientModel client);
|
||||
|
||||
Policy mapRolesCompositePermission(ClientModel client);
|
||||
|
||||
Policy managePermission(ClientModel client);
|
||||
|
||||
Policy configurePermission(ClientModel client);
|
||||
|
||||
Policy viewPermission(ClientModel client);
|
||||
|
||||
ResourceServer resourceServer(ClientModel client);
|
||||
}
|
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
* 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.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 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 "client.resource." + client.getId();
|
||||
}
|
||||
|
||||
private String getManagePermissionName(ClientModel client) {
|
||||
return "manage.permission.client." + client.getId();
|
||||
}
|
||||
private String getConfigurePermissionName(ClientModel client) {
|
||||
return "configure.permission.client." + client.getId();
|
||||
}
|
||||
private String getViewPermissionName(ClientModel client) {
|
||||
return "view.permission.client." + client.getId();
|
||||
}
|
||||
private String getMapRolesPermissionName(ClientModel client) {
|
||||
return MAP_ROLES_SCOPE + ".permission.client." + client.getId();
|
||||
}
|
||||
private String getMapRolesClientScopePermissionName(ClientModel client) {
|
||||
return MAP_ROLES_CLIENT_SCOPE + ".permission.client." + client.getId();
|
||||
}
|
||||
private String getMapRolesCompositePermissionName(ClientModel client) {
|
||||
return MAP_ROLES_COMPOSITE_SCOPE + ".permission.client." + client.getId();
|
||||
}
|
||||
|
||||
private void initialize(ClientModel client) {
|
||||
ResourceServer server = root.findOrCreateResourceServer(client);
|
||||
Scope manageScope = manageScope(server);
|
||||
if (manageScope == null) {
|
||||
manageScope = authz.getStoreFactory().getScopeStore().create(AdminPermissionManagement.MANAGE_SCOPE, server);
|
||||
}
|
||||
Scope viewScope = viewScope(server);
|
||||
if (viewScope == null) {
|
||||
viewScope = authz.getStoreFactory().getScopeStore().create(AdminPermissionManagement.VIEW_SCOPE, server);
|
||||
}
|
||||
Scope mapRoleScope = mapRolesScope(server);
|
||||
if (mapRoleScope == null) {
|
||||
mapRoleScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_SCOPE, server);
|
||||
}
|
||||
Scope mapRoleClientScope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_CLIENT_SCOPE, server.getId());
|
||||
if (mapRoleClientScope == null) {
|
||||
mapRoleClientScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_CLIENT_SCOPE, server);
|
||||
}
|
||||
Scope mapRoleCompositeScope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_COMPOSITE_SCOPE, server.getId());
|
||||
if (mapRoleCompositeScope == null) {
|
||||
mapRoleCompositeScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_COMPOSITE_SCOPE, server);
|
||||
}
|
||||
Scope configureScope = authz.getStoreFactory().getScopeStore().findByName(CONFIGURE_SCOPE, server.getId());
|
||||
if (configureScope == null) {
|
||||
configureScope = authz.getStoreFactory().getScopeStore().create(CONFIGURE_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());
|
||||
resource.setType("Client");
|
||||
Set<Scope> scopeset = new HashSet<>();
|
||||
scopeset.add(configureScope);
|
||||
scopeset.add(manageScope);
|
||||
scopeset.add(viewScope);
|
||||
scopeset.add(mapRoleScope);
|
||||
scopeset.add(mapRoleClientScope);
|
||||
scopeset.add(mapRoleCompositeScope);
|
||||
resource.updateScopes(scopeset);
|
||||
}
|
||||
String managePermissionName = getManagePermissionName(client);
|
||||
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
|
||||
if (managePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, managePermissionName, resource, manageScope);
|
||||
}
|
||||
String configurePermissionName = getConfigurePermissionName(client);
|
||||
Policy configurePermission = authz.getStoreFactory().getPolicyStore().findByName(configurePermissionName, server.getId());
|
||||
if (configurePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, configurePermissionName, resource, configureScope);
|
||||
}
|
||||
String viewPermissionName = getViewPermissionName(client);
|
||||
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
|
||||
if (viewPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, viewPermissionName, resource, viewScope);
|
||||
}
|
||||
String mapRolePermissionName = getMapRolesPermissionName(client);
|
||||
Policy mapRolePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRolePermissionName, server.getId());
|
||||
if (mapRolePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, mapRolePermissionName, resource, mapRoleScope);
|
||||
}
|
||||
String mapRoleClientScopePermissionName = getMapRolesClientScopePermissionName(client);
|
||||
Policy mapRoleClientScopePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRoleClientScopePermissionName, server.getId());
|
||||
if (mapRoleClientScopePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, mapRoleClientScopePermissionName, resource, mapRoleClientScope);
|
||||
}
|
||||
String mapRoleCompositePermissionName = getMapRolesCompositePermissionName(client);
|
||||
Policy mapRoleCompositePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRoleCompositePermissionName, server.getId());
|
||||
if (mapRoleCompositePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, mapRoleCompositePermissionName, resource, mapRoleCompositeScope);
|
||||
}
|
||||
}
|
||||
|
||||
private void deletePolicy(String name, ResourceServer server) {
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(name, server.getId());
|
||||
if (policy != null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void deletePermissions(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return;
|
||||
deletePolicy(getManagePermissionName(client), server);
|
||||
deletePolicy(getViewPermissionName(client), server);
|
||||
deletePolicy(getMapRolesPermissionName(client), server);
|
||||
deletePolicy(getMapRolesClientScopePermissionName(client), server);
|
||||
deletePolicy(getMapRolesCompositePermissionName(client), server);
|
||||
deletePolicy(getConfigurePermissionName(client), server);
|
||||
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 = resourceServer(client);
|
||||
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 configureScope(ResourceServer server) {
|
||||
return authz.getStoreFactory().getScopeStore().findByName(CONFIGURE_SCOPE, server.getId());
|
||||
}
|
||||
|
||||
private Scope viewScope(ResourceServer server) {
|
||||
return authz.getStoreFactory().getScopeStore().findByName(AdminPermissionManagement.VIEW_SCOPE, server.getId());
|
||||
}
|
||||
private Scope mapRolesScope(ResourceServer server) {
|
||||
return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireListTemplates() {
|
||||
if (!canListTemplates()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
public boolean canManageClientsDefault() {
|
||||
return root.hasOneAdminRole(AdminRoles.MANAGE_CLIENTS);
|
||||
}
|
||||
public boolean canViewClientDefault() {
|
||||
return root.hasOneAdminRole(AdminRoles.MANAGE_CLIENTS, AdminRoles.VIEW_CLIENTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canManage() {
|
||||
return canManageClientsDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireManage() {
|
||||
if (!canManage()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean canView() {
|
||||
return canManageClientsDefault() || canViewClientDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireView() {
|
||||
if (!canView()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource resource(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return null;
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
|
||||
if (resource == null) return null;
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getPermissions(ClientModel client) {
|
||||
Map<String, String> scopes = new HashMap<>();
|
||||
scopes.put(MAP_ROLES_SCOPE, mapRolesPermission(client).getId());
|
||||
scopes.put(MAP_ROLES_CLIENT_SCOPE, mapRolesClientScopePermission(client).getId());
|
||||
scopes.put(MAP_ROLES_COMPOSITE_SCOPE, mapRolesCompositePermission(client).getId());
|
||||
scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission(client).getId());
|
||||
scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission(client).getId());
|
||||
scopes.put(CONFIGURE_SCOPE, configurePermission(client).getId());
|
||||
return scopes;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canManage(ClientModel client) {
|
||||
if (canManageClientsDefault()) return true;
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getManagePermissionName(client), server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = manageScope(server);
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConfigure(ClientModel client) {
|
||||
if (canManage(client)) return true;
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getConfigurePermissionName(client), server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = configureScope(server);
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
}
|
||||
@Override
|
||||
public void requireConfigure(ClientModel client) {
|
||||
if (!canConfigure(client)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void requireManage(ClientModel client) {
|
||||
if (!canManage(client)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canView(ClientModel client) {
|
||||
return hasView(client) || canConfigure(client);
|
||||
}
|
||||
|
||||
private boolean hasView(ClientModel client) {
|
||||
if (canView()) return true;
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getViewPermissionName(client), server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 canManageClientsDefault();
|
||||
}
|
||||
|
||||
@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 canManageClientsDefault();
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMapRoles(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolesPermissionName(client), server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = mapRolesScope(server);
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy mapRolesPermission(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return null;
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(getMapRolesPermissionName(client), server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy mapRolesClientScopePermission(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return null;
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(getMapRolesClientScopePermissionName(client), server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy mapRolesCompositePermission(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return null;
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(getMapRolesCompositePermissionName(client), server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy managePermission(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return null;
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(getManagePermissionName(client), server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy configurePermission(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return null;
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(getConfigurePermissionName(client), server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy viewPermission(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return null;
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(getViewPermissionName(client), server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceServer resourceServer(ClientModel client) {
|
||||
return root.resourceServer(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMapCompositeRoles(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolesCompositePermissionName(client), server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_COMPOSITE_SCOPE, server.getId());
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
}
|
||||
@Override
|
||||
public boolean canMapClientScopeRoles(ClientModel client) {
|
||||
ResourceServer server = resourceServer(client);
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolesClientScopePermissionName(client), server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_CLIENT_SCOPE, server.getId());
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getAccess(ClientModel client) {
|
||||
Map<String, Boolean> map = new HashMap<>();
|
||||
map.put("view", canView(client));
|
||||
map.put("manage", canManage(client));
|
||||
map.put("configure", canConfigure(client));
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
boolean canManageMembership(GroupModel group);
|
||||
|
||||
void requireManageMembership(GroupModel group);
|
||||
|
||||
Map<String, Boolean> getAccess(GroupModel group);
|
||||
}
|
|
@ -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.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.Resource;
|
||||
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 manageMembershipPermission(GroupModel group);
|
||||
|
||||
Policy viewPermission(GroupModel group);
|
||||
Policy managePermission(GroupModel group);
|
||||
|
||||
Resource resource(GroupModel group);
|
||||
|
||||
Map<String, String> getPermissions(GroupModel group);
|
||||
|
||||
}
|
|
@ -0,0 +1,483 @@
|
|||
/*
|
||||
* 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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
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_MEMBERSHIP_SCOPE = "manage-membership";
|
||||
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." + group.getId();
|
||||
}
|
||||
|
||||
|
||||
public static String getManagePermissionGroup(GroupModel group) {
|
||||
return "manage.permission.group." + group.getId();
|
||||
}
|
||||
|
||||
public static String getManageMembersPermissionGroup(GroupModel group) {
|
||||
return "manage.members.permission.group." + group.getId();
|
||||
}
|
||||
|
||||
public static String getManageMembershipPermissionGroup(GroupModel group) {
|
||||
return "manage.membership.permission.group." + group.getId();
|
||||
}
|
||||
|
||||
public static String getViewPermissionGroup(GroupModel group) {
|
||||
return "view.permission.group." + group.getId();
|
||||
}
|
||||
|
||||
public static String getViewMembersPermissionGroup(GroupModel group) {
|
||||
return "view.members.permission.group." + group.getId();
|
||||
}
|
||||
|
||||
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);
|
||||
Scope manageMembershipScope = root.initializeRealmScope(MANAGE_MEMBERSHIP_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);
|
||||
scopeset.add(manageMembershipScope);
|
||||
scopeset.add(manageMembersScope);
|
||||
groupResource.updateScopes(scopeset);
|
||||
}
|
||||
String managePermissionName = getManagePermissionGroup(group);
|
||||
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
|
||||
if (managePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, managePermissionName, groupResource, manageScope);
|
||||
}
|
||||
String viewPermissionName = getViewPermissionGroup(group);
|
||||
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
|
||||
if (viewPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, viewPermissionName, groupResource, viewScope);
|
||||
}
|
||||
String manageMembersPermissionName = getManageMembersPermissionGroup(group);
|
||||
Policy manageMembersPermission = authz.getStoreFactory().getPolicyStore().findByName(manageMembersPermissionName, server.getId());
|
||||
if (manageMembersPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, manageMembersPermissionName, groupResource, manageMembersScope);
|
||||
}
|
||||
String viewMembersPermissionName = getViewMembersPermissionGroup(group);
|
||||
Policy viewMembersPermission = authz.getStoreFactory().getPolicyStore().findByName(viewMembersPermissionName, server.getId());
|
||||
if (viewMembersPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, viewMembersPermissionName, groupResource, viewMembersScope);
|
||||
}
|
||||
String manageMembershipPermissionName = getManageMembershipPermissionGroup(group);
|
||||
Policy manageMembershipPermission = authz.getStoreFactory().getPolicyStore().findByName(manageMembershipPermissionName, server.getId());
|
||||
if (manageMembershipPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, manageMembershipPermissionName, groupResource, manageMembershipScope);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canList() {
|
||||
return root.hasOneAdminRole(AdminRoles.VIEW_USERS, AdminRoles.MANAGE_USERS, AdminRoles.QUERY_GROUPS);
|
||||
}
|
||||
|
||||
@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 = managePermission(group);
|
||||
if (managePermission != null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(managePermission.getId());
|
||||
}
|
||||
Policy viewPermission = viewPermission(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 manageMembershipPermission(GroupModel group) {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return null;
|
||||
String manageMembershipPermissionName = getManageMembershipPermissionGroup(group);
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(manageMembershipPermissionName, server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy viewPermission(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 managePermission(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 Resource resource(GroupModel group) {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return null;
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
|
||||
if (resource == null) return null;
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getPermissions(GroupModel group) {
|
||||
Map<String, String> scopes = new HashMap<>();
|
||||
scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission(group).getId());
|
||||
scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission(group).getId());
|
||||
scopes.put(MANAGE_MEMBERS_SCOPE, manageMembersPermission(group).getId());
|
||||
scopes.put(VIEW_MEMBERS_SCOPE, viewMembersPermission(group).getId());
|
||||
scopes.put(MANAGE_MEMBERSHIP_SCOPE, manageMembershipPermission(group).getId());
|
||||
return scopes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canManage(GroupModel group) {
|
||||
if (canManage()) return true;
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = managePermission(group);
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
return hasView(group) || canManage(group);
|
||||
}
|
||||
|
||||
private boolean hasView(GroupModel group) {
|
||||
if (canView()) return true;
|
||||
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = viewPermission(group);
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then abort
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
return canViewMembersEvaluation(group) || canManageMembers(group);
|
||||
}
|
||||
|
||||
private boolean canViewMembersEvaluation(GroupModel group) {
|
||||
if (root.users().canView()) return true;
|
||||
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = viewMembersPermission(group);
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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.users().canManage()) return true;
|
||||
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = manageMembersPermission(group);
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canManageMembership(GroupModel group) {
|
||||
if (canManage(group)) return true;
|
||||
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return false;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = manageMembershipPermission(group);
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MANAGE_MEMBERSHIP_SCOPE, server.getId());
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireManageMembership(GroupModel group) {
|
||||
if (!canManageMembership(group)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getAccess(GroupModel group) {
|
||||
Map<String, Boolean> map = new HashMap<>();
|
||||
map.put("view", canView(group));
|
||||
map.put("manage", canManage(group));
|
||||
map.put("manageMembership", canManageMembership(group));
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.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.ClientModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
class Helper {
|
||||
public static Policy addScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope, Policy policy) {
|
||||
ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
|
||||
|
||||
representation.setName(name);
|
||||
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||
representation.setLogic(Logic.POSITIVE);
|
||||
representation.addResource(resource.getName());
|
||||
representation.addScope(scope.getName());
|
||||
representation.addPolicy(policy.getName());
|
||||
|
||||
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||
}
|
||||
|
||||
public static Policy addEmptyScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope) {
|
||||
ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
|
||||
|
||||
representation.setName(name);
|
||||
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||
representation.setLogic(Logic.POSITIVE);
|
||||
representation.addResource(resource.getName());
|
||||
representation.addScope(scope.getName());
|
||||
|
||||
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||
}
|
||||
|
||||
public static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
|
||||
String roleName = getRolePolicyName(role);
|
||||
return createRolePolicy(authz, resourceServer, role, roleName);
|
||||
}
|
||||
|
||||
public static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role, String policyName) {
|
||||
PolicyRepresentation representation = new PolicyRepresentation();
|
||||
|
||||
representation.setName(policyName);
|
||||
representation.setType("role");
|
||||
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||
representation.setLogic(Logic.POSITIVE);
|
||||
String roleValues = "[{\"id\":\"" + role.getId() + "\",\"required\": true}]";
|
||||
Map<String, String> config = new HashMap<>();
|
||||
config.put("roles", roleValues);
|
||||
representation.setConfig(config);
|
||||
|
||||
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||
}
|
||||
|
||||
public static String getRolePolicyName(RoleModel role) {
|
||||
String roleName = "";
|
||||
if (role.getContainer() instanceof ClientModel) {
|
||||
ClientModel client = (ClientModel) role.getContainer();
|
||||
roleName = client.getClientId() + "." + role.getName();
|
||||
} else {
|
||||
roleName = role.getName();
|
||||
}
|
||||
roleName = "role.policy." + roleName;
|
||||
return roleName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* 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.RoleModel;
|
||||
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, RealmsPermissionEvaluator {
|
||||
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)
|
||||
|| auth.getClient().getClientId().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
|
||||
this.identity = new UserModelIdentity(auth.getRealm(), auth.getUser());
|
||||
|
||||
} else {
|
||||
this.identity = new KeycloakIdentity(auth.getToken(), session);
|
||||
}
|
||||
}
|
||||
MgmtPermissions(KeycloakSession session, AdminAuth auth) {
|
||||
this.session = session;
|
||||
this.auth = auth;
|
||||
this.admin = auth.getUser();
|
||||
this.adminsRealm = auth.getRealm();
|
||||
if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)
|
||||
|| auth.getClient().getClientId().equals(Constants.ADMIN_CONSOLE_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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationProvider authz() {
|
||||
return authz;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void requireAnyAdminRole() {
|
||||
if (!hasAnyAdminRole()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasAnyAdminRole() {
|
||||
return hasOneAdminRole(AdminRoles.ALL_REALM_ROLES);
|
||||
}
|
||||
|
||||
public boolean hasAnyAdminRole(RealmModel realm) {
|
||||
return hasOneAdminRole(realm, AdminRoles.ALL_REALM_ROLES);
|
||||
}
|
||||
|
||||
public boolean hasOneAdminRole(String... adminRoles) {
|
||||
String clientId;
|
||||
RealmModel realm = this.realm;
|
||||
return hasOneAdminRole(realm, adminRoles);
|
||||
}
|
||||
|
||||
public boolean hasOneAdminRole(RealmModel realm, String... adminRoles) {
|
||||
String clientId;
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
if (adminsRealm.equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||
clientId = realm.getMasterAdminClient().getClientId();
|
||||
} else if (adminsRealm.equals(realm)) {
|
||||
clientId = realm.getClientByClientId(realmManager.getRealmAdminClientId(realm)).getClientId();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
return initializeRealmResourceServer();
|
||||
}
|
||||
|
||||
public ResourceServer resourceServer(ClientModel client) {
|
||||
return realmResourceServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceServer realmResourceServer() {
|
||||
if (realmResourceServer != null) return realmResourceServer;
|
||||
ResourceServerStore resourceServerStore = authz.getStoreFactory().getResourceServerStore();
|
||||
ClientModel client = getRealmManagementClient();
|
||||
if (client == null) return null;
|
||||
realmResourceServer = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||
return realmResourceServer;
|
||||
|
||||
}
|
||||
|
||||
public ResourceServer initializeRealmResourceServer() {
|
||||
if (realmResourceServer != null) return realmResourceServer;
|
||||
ClientModel client = getRealmManagementClient();
|
||||
realmResourceServer = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||
if (realmResourceServer == null) {
|
||||
realmResourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
|
||||
}
|
||||
return realmResourceServer;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
return evaluatePermission(resource, scope, resourceServer, identity);
|
||||
}
|
||||
|
||||
public boolean evaluatePermission(Resource resource, Scope scope, ResourceServer resourceServer, Identity identity) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canView(RealmModel realm) {
|
||||
return hasOneAdminRole(realm, AdminRoles.VIEW_REALM, AdminRoles.MANAGE_REALM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdmin(RealmModel realm) {
|
||||
return hasAnyAdminRole(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdmin() {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
if (adminsRealm.equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||
if (identity.hasRealmRole(AdminRoles.ADMIN) || identity.hasRealmRole(AdminRoles.CREATE_REALM)) {
|
||||
return true;
|
||||
}
|
||||
for (RealmModel realm : session.realms().getRealms()) {
|
||||
if (isAdmin(realm)) return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return isAdmin(adminsRealm);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateRealm() {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||
return false;
|
||||
}
|
||||
return identity.hasRealmRole(AdminRoles.CREATE_REALM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireCreateRealm() {
|
||||
if (!canCreateRealm()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -15,24 +15,21 @@
|
|||
* 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.ClientModel;
|
||||
import org.keycloak.models.ImpersonationConstants;
|
||||
import org.keycloak.services.ForbiddenException;
|
||||
import org.keycloak.services.resources.admin.AdminAuth;
|
||||
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class RealmAuth {
|
||||
class RealmAuth {
|
||||
|
||||
private Resource resource;
|
||||
|
||||
public enum Resource {
|
||||
CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION, AUTHORIZATION
|
||||
}
|
||||
private AdminAuth.Resource resource;
|
||||
|
||||
private AdminAuth auth;
|
||||
private ClientModel realmAdminApp;
|
||||
|
@ -42,7 +39,7 @@ public class RealmAuth {
|
|||
this.realmAdminApp = realmAdminApp;
|
||||
}
|
||||
|
||||
public RealmAuth init(Resource resource) {
|
||||
public RealmAuth init(AdminAuth.Resource resource) {
|
||||
this.resource = resource;
|
||||
return this;
|
||||
}
|
||||
|
@ -52,11 +49,15 @@ public class RealmAuth {
|
|||
}
|
||||
|
||||
public void requireAny() {
|
||||
if (!auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) {
|
||||
if (!hasAny()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasAny() {
|
||||
return auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES);
|
||||
}
|
||||
|
||||
public boolean hasView() {
|
||||
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) {
|
||||
case CLIENT:
|
||||
return AdminRoles.VIEW_CLIENTS;
|
||||
|
@ -96,7 +97,7 @@ public class RealmAuth {
|
|||
}
|
||||
}
|
||||
|
||||
private String getManageRole(Resource resource) {
|
||||
private String getManageRole(AdminAuth.Resource resource) {
|
||||
switch (resource) {
|
||||
case CLIENT:
|
||||
return AdminRoles.MANAGE_CLIENTS;
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.RealmModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface RealmPermissionEvaluator {
|
||||
boolean canListRealms();
|
||||
|
||||
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,189 @@
|
|||
/*
|
||||
* 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 canListRealms() {
|
||||
return root.hasAnyAdminRole();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireViewRealmNameList() {
|
||||
if (!canListRealms()) {
|
||||
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 (!canManageAuthorization()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void requireViewAuthorization() {
|
||||
if (!canViewAuthorization()) {
|
||||
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,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.models.RealmModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface RealmsPermissionEvaluator {
|
||||
boolean canView(RealmModel realm);
|
||||
|
||||
boolean isAdmin(RealmModel realm);
|
||||
|
||||
boolean isAdmin();
|
||||
|
||||
boolean canCreateRealm();
|
||||
|
||||
void requireCreateRealm();
|
||||
}
|
|
@ -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.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);
|
||||
|
||||
boolean canManage(RoleContainerModel container);
|
||||
|
||||
void requireManage(RoleContainerModel container);
|
||||
|
||||
boolean canView(RoleContainerModel container);
|
||||
|
||||
void requireView(RoleContainerModel container);
|
||||
|
||||
}
|
|
@ -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,585 @@
|
|||
/*
|
||||
* 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.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.ImpersonationConstants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.services.ForbiddenException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
initialize(role);
|
||||
} else {
|
||||
disablePermissions(role);
|
||||
}
|
||||
}
|
||||
|
||||
private void disablePermissions(RoleModel role) {
|
||||
ResourceServer server = resourceServer(role);
|
||||
if (server == null) return;
|
||||
Policy policy = mapRolePermission(role);
|
||||
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
policy = mapClientScopePermission(role);
|
||||
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
policy = mapCompositePermission(role);
|
||||
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
|
||||
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.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;
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy mapCompositePermission(RoleModel role) {
|
||||
ResourceServer server = resourceServer(role);
|
||||
if (server == 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;
|
||||
|
||||
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 root.resourceServer(client);
|
||||
}
|
||||
|
||||
private boolean checkAdminRoles(RoleModel role) {
|
||||
if (AdminRoles.ALL_ROLES.contains(role.getName())) {
|
||||
if (root.admin().hasRole(role)) return true;
|
||||
|
||||
ClientModel adminClient = root.getRealmManagementClient();
|
||||
if (adminClient.equals(role.getContainer())) {
|
||||
// if this is realm admin role, then check to see if admin has similar permissions
|
||||
// we do this so that the authz service is invoked
|
||||
if (role.getName().equals(AdminRoles.MANAGE_CLIENTS)) {
|
||||
if (!root.clients().canManage()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.VIEW_CLIENTS)) {
|
||||
if (!root.clients().canView()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.QUERY_CLIENTS)) {
|
||||
return true;
|
||||
} else if (role.getName().equals(AdminRoles.QUERY_USERS)) {
|
||||
return true;
|
||||
} else if (role.getName().equals(AdminRoles.QUERY_GROUPS)) {
|
||||
return true;
|
||||
} else if (role.getName().equals(AdminRoles.MANAGE_AUTHORIZATION)) {
|
||||
if (!root.realm().canManageAuthorization()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.VIEW_AUTHORIZATION)) {
|
||||
if (!root.realm().canViewAuthorization()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.MANAGE_EVENTS)) {
|
||||
if (!root.realm().canManageEvents()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.VIEW_EVENTS)) {
|
||||
if (!root.realm().canViewEvents()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.MANAGE_USERS)) {
|
||||
if (!root.users().canManage()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.VIEW_USERS)) {
|
||||
if (!root.users().canView()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.MANAGE_IDENTITY_PROVIDERS)) {
|
||||
if (!root.realm().canManageIdentityProviders()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.VIEW_IDENTITY_PROVIDERS)) {
|
||||
if (!root.realm().canViewIdentityProviders()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.MANAGE_REALM)) {
|
||||
if (!root.realm().canManageRealm()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(AdminRoles.VIEW_REALM)) {
|
||||
if (!root.realm().canViewRealm()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (role.getName().equals(ImpersonationConstants.IMPERSONATION_ROLE)) {
|
||||
if (!root.users().canImpersonate()) {
|
||||
return adminConflictMessage(role);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return adminConflictMessage(role);
|
||||
}
|
||||
|
||||
} else {
|
||||
// now we need to check to see if this is a master admin role
|
||||
if (role.getContainer() instanceof RealmModel) {
|
||||
RealmModel realm = (RealmModel)role.getContainer();
|
||||
// If realm role is master admin role then abort
|
||||
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||
return adminConflictMessage(role);
|
||||
}
|
||||
} else {
|
||||
ClientModel container = (ClientModel)role.getContainer();
|
||||
// abort if this is an role in master realm and role is an admin role of any realm
|
||||
if (container.getRealm().getName().equals(Config.getAdminRealm())
|
||||
&& container.getClientId().endsWith("-realm")) {
|
||||
return adminConflictMessage(role);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private boolean adminConflictMessage(RoleModel role) {
|
||||
logger.debug("Trying to assign admin privileges of role: " + role.getName() + " but admin doesn't have same privilege");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is admin allowed to map this role?
|
||||
*
|
||||
* @param role
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean canMapRole(RoleModel role) {
|
||||
if (root.users().canManageDefault()) return checkAdminRoles(role);
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (role.getContainer() instanceof ClientModel) {
|
||||
if (root.clients().canMapRoles((ClientModel)role.getContainer())) return true;
|
||||
}
|
||||
if (!isPermissionsEnabled(role)){
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer resourceServer = resourceServer(role);
|
||||
if (resourceServer == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), resourceServer.getId());
|
||||
if (policy == null || policy.getAssociatedPolicies().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Resource roleResource = resource(role);
|
||||
Scope mapRoleScope = mapRoleScope(resourceServer);
|
||||
if (root.evaluatePermission(roleResource, mapRoleScope, resourceServer)) {
|
||||
return checkAdminRoles(role);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@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 canManage(RoleContainerModel container) {
|
||||
if (container instanceof RealmModel) {
|
||||
return root.realm().canManageRealm();
|
||||
} else {
|
||||
return root.clients().canConfigure((ClientModel)container);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireManage(RoleContainerModel container) {
|
||||
if (!canManage(container)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canView(RoleContainerModel container) {
|
||||
if (container instanceof RealmModel) {
|
||||
return root.realm().canViewRealm();
|
||||
} else {
|
||||
return root.clients().canView((ClientModel)container);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireView(RoleContainerModel container) {
|
||||
if (!canView(container)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMapComposite(RoleModel role) {
|
||||
if (canManageDefault(role)) return checkAdminRoles(role);
|
||||
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
if (role.getContainer() instanceof ClientModel) {
|
||||
if (root.clients().canMapCompositeRoles((ClientModel)role.getContainer())) return true;
|
||||
}
|
||||
if (!isPermissionsEnabled(role)){
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer resourceServer = resourceServer(role);
|
||||
if (resourceServer == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapCompositePermissionName(role), resourceServer.getId());
|
||||
if (policy == null || policy.getAssociatedPolicies().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Resource roleResource = resource(role);
|
||||
Scope scope = mapCompositeScope(resourceServer);
|
||||
if (root.evaluatePermission(roleResource, scope, resourceServer)) {
|
||||
return checkAdminRoles(role);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireMapComposite(RoleModel role) {
|
||||
if (!canMapComposite(role)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canMapClientScope(RoleModel role) {
|
||||
if (root.clients().canManageClientsDefault()) return true;
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
if (role.getContainer() instanceof ClientModel) {
|
||||
if (root.clients().canMapClientScopeRoles((ClientModel)role.getContainer())) return true;
|
||||
}
|
||||
if (!isPermissionsEnabled(role)){
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceServer resourceServer = resourceServer(role);
|
||||
if (resourceServer == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapClientScopePermissionName(role), resourceServer.getId());
|
||||
if (policy == null || policy.getAssociatedPolicies().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Resource roleResource = resource(role);
|
||||
Scope scope = mapClientScope(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;
|
||||
}
|
||||
|
||||
public boolean canManageDefault(RoleModel role) {
|
||||
if (role.getContainer() instanceof RealmModel) {
|
||||
return root.realm().canManageRealmDefault();
|
||||
} else if (role.getContainer() instanceof ClientModel) {
|
||||
ClientModel client = (ClientModel)role.getContainer();
|
||||
return root.clients().canManageClientsDefault();
|
||||
}
|
||||
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 mapRoleScope(ResourceServer server) {
|
||||
return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_SCOPE, server.getId());
|
||||
}
|
||||
|
||||
private Scope mapClientScope(ResourceServer server) {
|
||||
return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_CLIENT_SCOPE_SCOPE, server.getId());
|
||||
}
|
||||
|
||||
private Scope mapCompositeScope(ResourceServer server) {
|
||||
return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_COMPOSITE_SCOPE, server.getId());
|
||||
}
|
||||
|
||||
|
||||
private void initialize(RoleModel role) {
|
||||
ResourceServer server = resourceServer(role);
|
||||
if (server == null) {
|
||||
ClientModel client = getRoleClient(role);
|
||||
server = root.findOrCreateResourceServer(client);
|
||||
}
|
||||
Scope mapRoleScope = mapRoleScope(server);
|
||||
if (mapRoleScope == null) {
|
||||
mapRoleScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_SCOPE, server);
|
||||
}
|
||||
Scope mapClientScope = mapClientScope(server);
|
||||
if (mapClientScope == null) {
|
||||
mapClientScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_CLIENT_SCOPE_SCOPE, server);
|
||||
}
|
||||
Scope mapCompositeScope = mapCompositeScope(server);
|
||||
if (mapCompositeScope == null) {
|
||||
mapCompositeScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_COMPOSITE_SCOPE, server);
|
||||
}
|
||||
|
||||
String roleResourceName = getRoleResourceName(role);
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(roleResourceName, server.getId());
|
||||
if (resource == null) {
|
||||
resource = authz.getStoreFactory().getResourceStore().create(roleResourceName, server, server.getClientId());
|
||||
Set<Scope> scopeset = new HashSet<>();
|
||||
scopeset.add(mapClientScope);
|
||||
scopeset.add(mapCompositeScope);
|
||||
scopeset.add(mapRoleScope);
|
||||
resource.updateScopes(scopeset);
|
||||
resource.setType("Role");
|
||||
}
|
||||
Policy mapRolePermission = mapRolePermission(role);
|
||||
if (mapRolePermission == null) {
|
||||
mapRolePermission = Helper.addEmptyScopePermission(authz, server, getMapRolePermissionName(role), resource, mapRoleScope);
|
||||
mapRolePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
|
||||
}
|
||||
|
||||
Policy mapClientScopePermission = mapClientScopePermission(role);
|
||||
if (mapClientScopePermission == null) {
|
||||
mapClientScopePermission = Helper.addEmptyScopePermission(authz, server, getMapClientScopePermissionName(role), resource, mapClientScope);
|
||||
mapClientScopePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
|
||||
}
|
||||
|
||||
Policy mapCompositePermission = mapCompositePermission(role);
|
||||
if (mapCompositePermission == null) {
|
||||
mapCompositePermission = Helper.addEmptyScopePermission(authz, server, getMapCompositePermissionName(role), resource, mapCompositeScope);
|
||||
mapCompositePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
|
||||
}
|
||||
}
|
||||
|
||||
private String getMapRolePermissionName(RoleModel role) {
|
||||
return MAP_ROLE_SCOPE + ".permission." + role.getId();
|
||||
}
|
||||
|
||||
private String getMapClientScopePermissionName(RoleModel role) {
|
||||
return MAP_ROLE_CLIENT_SCOPE_SCOPE + ".permission." + role.getId();
|
||||
}
|
||||
|
||||
private String getMapCompositePermissionName(RoleModel role) {
|
||||
return MAP_ROLE_COMPOSITE_SCOPE + ".permission." + role.getId();
|
||||
}
|
||||
|
||||
private ResourceServer sdfgetResourceServer(RoleModel role) {
|
||||
ClientModel client = getRoleClient(role);
|
||||
return root.findOrCreateResourceServer(client);
|
||||
}
|
||||
|
||||
private static String getRoleResourceName(RoleModel role) {
|
||||
return "role.resource." + role.getId();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.UserModel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @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 canQuery(UserModel user);
|
||||
|
||||
void requireQuery(UserModel user);
|
||||
|
||||
boolean canView();
|
||||
boolean canView(UserModel user);
|
||||
void requireView(UserModel user);
|
||||
|
||||
void requireView();
|
||||
|
||||
boolean canImpersonate(UserModel user);
|
||||
|
||||
boolean canImpersonate();
|
||||
|
||||
void requireImpersonate(UserModel user);
|
||||
|
||||
Map<String, Boolean> getAccess(UserModel user);
|
||||
|
||||
boolean canMapRoles(UserModel user);
|
||||
|
||||
void requireMapRoles(UserModel user);
|
||||
|
||||
boolean canManageGroupMembership(UserModel user);
|
||||
|
||||
void requireManageGroupMembership(UserModel user);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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();
|
||||
|
||||
Policy manageGroupMembershipPermission();
|
||||
|
||||
Policy mapRolesPermission();
|
||||
|
||||
Policy adminImpersonatingPermission();
|
||||
|
||||
Policy userImpersonatedPermission();
|
||||
}
|
|
@ -0,0 +1,635 @@
|
|||
/*
|
||||
* 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.common.UserModelIdentity;
|
||||
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.models.AdminRoles;
|
||||
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 MAP_ROLES_SCOPE="map-roles";
|
||||
public static final String IMPERSONATE_SCOPE="impersonate";
|
||||
public static final String USER_IMPERSONATED_SCOPE="user-impersonated";
|
||||
public static final String MANAGE_GROUP_MEMBERSHIP_SCOPE="manage-group-membership";
|
||||
public static final String MAP_ROLES_PERMISSION_USERS = "map-roles.permission.users";
|
||||
public static final String ADMIN_IMPERSONATING_PERMISSION = "admin-impersonating.permission.users";
|
||||
public static final String USER_IMPERSONATED_PERMISSION = "user-impersonated.permission.users";
|
||||
public static final String MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS = "manage-group-membership.permission.users";
|
||||
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();
|
||||
Scope mapRolesScope = root.initializeRealmScope(MAP_ROLES_SCOPE);
|
||||
Scope impersonateScope = root.initializeRealmScope(IMPERSONATE_SCOPE);
|
||||
Scope userImpersonatedScope = root.initializeRealmScope(USER_IMPERSONATED_SCOPE);
|
||||
Scope manageGroupMembershipScope = root.initializeRealmScope(MANAGE_GROUP_MEMBERSHIP_SCOPE);
|
||||
|
||||
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);
|
||||
scopeset.add(mapRolesScope);
|
||||
scopeset.add(impersonateScope);
|
||||
scopeset.add(manageGroupMembershipScope);
|
||||
scopeset.add(userImpersonatedScope);
|
||||
usersResource.updateScopes(scopeset);
|
||||
}
|
||||
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
|
||||
if (managePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, MANAGE_PERMISSION_USERS, usersResource, manageScope);
|
||||
}
|
||||
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
|
||||
if (viewPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, VIEW_PERMISSION_USERS, usersResource, viewScope);
|
||||
}
|
||||
Policy mapRolesPermission = authz.getStoreFactory().getPolicyStore().findByName(MAP_ROLES_PERMISSION_USERS, server.getId());
|
||||
if (mapRolesPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, MAP_ROLES_PERMISSION_USERS, usersResource, mapRolesScope);
|
||||
}
|
||||
Policy membershipPermission = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
|
||||
if (membershipPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, usersResource, manageGroupMembershipScope);
|
||||
}
|
||||
Policy impersonatePermission = authz.getStoreFactory().getPolicyStore().findByName(ADMIN_IMPERSONATING_PERMISSION, server.getId());
|
||||
if (impersonatePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, ADMIN_IMPERSONATING_PERMISSION, usersResource, impersonateScope);
|
||||
}
|
||||
impersonatePermission = authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, server.getId());
|
||||
if (impersonatePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, USER_IMPERSONATED_PERMISSION, usersResource, userImpersonatedScope);
|
||||
}
|
||||
}
|
||||
|
||||
@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());
|
||||
scopes.put(MAP_ROLES_SCOPE, mapRolesPermission().getId());
|
||||
scopes.put(MANAGE_GROUP_MEMBERSHIP_SCOPE, manageGroupMembershipPermission().getId());
|
||||
scopes.put(IMPERSONATE_SCOPE, adminImpersonatingPermission().getId());
|
||||
scopes.put(USER_IMPERSONATED_SCOPE, userImpersonatedPermission().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 = managePermission();
|
||||
|
||||
return policy != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermissionsEnabled(boolean enable) {
|
||||
if (enable) {
|
||||
initialize();
|
||||
} else {
|
||||
deletePermissionSetup();
|
||||
}
|
||||
}
|
||||
|
||||
private void deletePermissionSetup() {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return;
|
||||
Policy policy = managePermission();
|
||||
if (policy == null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
}
|
||||
policy = viewPermission();
|
||||
if (policy == null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
}
|
||||
policy = mapRolesPermission();
|
||||
if (policy == null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
}
|
||||
policy = manageGroupMembershipPermission();
|
||||
if (policy == null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
}
|
||||
policy = adminImpersonatingPermission();
|
||||
if (policy == null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
}
|
||||
policy = userImpersonatedPermission();
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy manageGroupMembershipPermission() {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy mapRolesPermission() {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(MAP_ROLES_PERMISSION_USERS, server.getId());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Policy adminImpersonatingPermission() {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(ADMIN_IMPERSONATING_PERMISSION, server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy userImpersonatedPermission() {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, 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 (canManageDefault()) return true;
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 canView() || root.hasOneAdminRole(AdminRoles.QUERY_USERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireQuery() {
|
||||
if (!canQuery()) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canQuery(UserModel user) {
|
||||
return canView(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireQuery(UserModel user) {
|
||||
if (!canQuery(user)) {
|
||||
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 (canViewDefault()) return true;
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasViewPermission() || canManage();
|
||||
}
|
||||
|
||||
private boolean hasViewPermission() {
|
||||
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() || canViewByGroup(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireView(UserModel user) {
|
||||
if (!canView(user)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireView() {
|
||||
if (!(canView())) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canImpersonate(UserModel user) {
|
||||
if (!canImpersonate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Identity userIdentity = new UserModelIdentity(root.realm, user);
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return true;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||
if (resource == null) return true;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, server.getId());
|
||||
if (policy == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Scope scope = root.realmScope(USER_IMPERSONATED_SCOPE);
|
||||
return root.evaluatePermission(resource, scope, server, userIdentity);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canImpersonate() {
|
||||
if (root.hasOneAdminRole(ImpersonationConstants.IMPERSONATION_ROLE)) return true;
|
||||
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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(ADMIN_IMPERSONATING_PERMISSION, server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = root.realmScope(IMPERSONATE_SCOPE);
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireImpersonate(UserModel user) {
|
||||
if (!canImpersonate(user)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getAccess(UserModel user) {
|
||||
Map<String, Boolean> map = new HashMap<>();
|
||||
map.put("view", canView(user));
|
||||
map.put("manage", canManage(user));
|
||||
map.put("mapRoles", canMapRoles(user));
|
||||
map.put("manageGroupMembership", canManageGroupMembership(user));
|
||||
map.put("impersonate", canImpersonate(user));
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMapRoles(UserModel user) {
|
||||
if (canManage(user)) return true;
|
||||
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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(MAP_ROLES_PERMISSION_USERS, server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = root.realmScope(MAP_ROLES_SCOPE);
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireMapRoles(UserModel user) {
|
||||
if (!canMapRoles(user)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canManageGroupMembership(UserModel user) {
|
||||
if (canManage(user)) return true;
|
||||
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = root.realmScope(MANAGE_GROUP_MEMBERSHIP_SCOPE);
|
||||
return root.evaluatePermission(resource, scope, server);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requireManageGroupMembership(UserModel user) {
|
||||
if (!canManageGroupMembership(user)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -43,6 +43,14 @@ import static org.keycloak.testsuite.util.IOUtil.PROJECT_BUILD_DIRECTORY;
|
|||
public class AdminClientUtil {
|
||||
|
||||
public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String authServerContextRoot) throws Exception {
|
||||
return createAdminClient(ignoreUnknownProperties, authServerContextRoot, MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
|
||||
}
|
||||
public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String realmName, String username, String password, String clientId, String clientSecret) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {
|
||||
return createAdminClient(ignoreUnknownProperties, AuthServerTestEnricher.getAuthServerContextRoot(), realmName, username, password, clientId, clientSecret);
|
||||
}
|
||||
|
||||
public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String authServerContextRoot, String realmName, String username, String password, String clientId, String clientSecret) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {
|
||||
SSLContext ssl = null;
|
||||
if ("true".equals(System.getProperty("auth.server.ssl.required"))) {
|
||||
File trustore = new File(PROJECT_BUILD_DIRECTORY, "dependency/keystore/keycloak.truststore");
|
||||
|
@ -63,13 +71,17 @@ public class AdminClientUtil {
|
|||
}
|
||||
|
||||
return Keycloak.getInstance(authServerContextRoot + "/auth",
|
||||
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID, null, ssl, jacksonProvider);
|
||||
realmName, username, password, clientId, clientSecret, ssl, jacksonProvider);
|
||||
}
|
||||
|
||||
public static Keycloak createAdminClient() throws Exception {
|
||||
return createAdminClient(false, AuthServerTestEnricher.getAuthServerContextRoot());
|
||||
}
|
||||
|
||||
public static Keycloak createAdminClient(boolean ignoreUnknownProperties) throws Exception {
|
||||
return createAdminClient(ignoreUnknownProperties, AuthServerTestEnricher.getAuthServerContextRoot());
|
||||
}
|
||||
|
||||
private static SSLContext getSSLContextWithTrustore(File file, String password) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {
|
||||
if (!file.isFile()) {
|
||||
throw new RuntimeException("Truststore file not found: " + file.getAbsolutePath());
|
||||
|
|
|
@ -167,6 +167,7 @@ public abstract class AbstractKeycloakTest {
|
|||
removeRealm(testRealm.getRealm());
|
||||
}
|
||||
} else {
|
||||
log.info("calling all TestCleanup");
|
||||
// Logout all users after the test
|
||||
List<RealmRepresentation> realms = testContext.getTestRealmReps();
|
||||
for (RealmRepresentation realm : realms) {
|
||||
|
@ -175,7 +176,12 @@ public abstract class AbstractKeycloakTest {
|
|||
|
||||
// Cleanup objects
|
||||
for (TestCleanup cleanup : testContext.getCleanups().values()) {
|
||||
cleanup.executeCleanup();
|
||||
try {
|
||||
if (cleanup != null) cleanup.executeCleanup();
|
||||
} catch (Exception e) {
|
||||
log.error("failed cleanup!", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
testContext.getCleanups().clear();
|
||||
}
|
||||
|
|
|
@ -479,8 +479,8 @@ public class ClientTest extends AbstractAdminTest {
|
|||
// Create foo mapper
|
||||
ProtocolMapperRepresentation fooMapper = new ProtocolMapperRepresentation();
|
||||
fooMapper.setName("foo");
|
||||
fooMapper.setProtocol("fooProtocol");
|
||||
fooMapper.setProtocolMapper("fooMapper");
|
||||
fooMapper.setProtocol("openid-connect");
|
||||
fooMapper.setProtocolMapper("oidc-hardcoded-claim-mapper");
|
||||
fooMapper.setConsentRequired(true);
|
||||
Response response = mappersResource.createMapper(fooMapper);
|
||||
String location = response.getLocation().toString();
|
||||
|
@ -493,13 +493,13 @@ public class ClientTest extends AbstractAdminTest {
|
|||
assertEquals(fooMapper.getName(), "foo");
|
||||
|
||||
// Update foo mapper
|
||||
fooMapper.setProtocolMapper("foo-mapper-updated");
|
||||
fooMapper.setConsentRequired(false);
|
||||
mappersResource.update(fooMapperId, fooMapper);
|
||||
|
||||
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), fooMapper, ResourceType.PROTOCOL_MAPPER);
|
||||
|
||||
fooMapper = mappersResource.getMapperById(fooMapperId);
|
||||
assertEquals(fooMapper.getProtocolMapper(), "foo-mapper-updated");
|
||||
assertFalse(fooMapper.isConsentRequired());
|
||||
|
||||
// Remove foo mapper
|
||||
mappersResource.delete(fooMapperId);
|
||||
|
|
|
@ -1,215 +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.testsuite.admin;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
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.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
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.Logic;
|
||||
import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
|
||||
import org.keycloak.representations.idm.authorization.PolicyEvaluationResponse;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@Ignore
|
||||
public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation testRealmRep = new RealmRepresentation();
|
||||
testRealmRep.setId(TEST);
|
||||
testRealmRep.setRealm(TEST);
|
||||
testRealmRep.setEnabled(true);
|
||||
testRealms.add(testRealmRep);
|
||||
}
|
||||
|
||||
public static void setupDefaults(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
|
||||
ClientModel client = realm.getClientByClientId("realm-management");
|
||||
|
||||
AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
|
||||
ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
|
||||
Scope mapRoleScope = authz.getStoreFactory().getScopeStore().create("map-role", resourceServer);
|
||||
Scope manageScope = authz.getStoreFactory().getScopeStore().create("manage", resourceServer);
|
||||
|
||||
Policy manageUsersPolicy = null;
|
||||
Policy manageClientsPolicy = null;
|
||||
for (RoleModel role : client.getRoles()) {
|
||||
Policy policy = createRolePolicy(authz, resourceServer, role);
|
||||
if (role.getName().equals(AdminRoles.MANAGE_USERS)) {
|
||||
manageUsersPolicy = policy;
|
||||
} else if (role.getName().equals(AdminRoles.MANAGE_CLIENTS)) {
|
||||
manageClientsPolicy = policy;
|
||||
}
|
||||
Resource resource = createRoleResource(authz, resourceServer, role);
|
||||
Set<Scope> scopeset = new HashSet<>();
|
||||
scopeset.add(mapRoleScope);
|
||||
resource.updateScopes(scopeset);
|
||||
|
||||
|
||||
String name = "map.role.permission." + client.getClientId() + "." + role.getName();
|
||||
Policy permission = addScopePermission(authz, resourceServer, name, resource, mapRoleScope, policy);
|
||||
|
||||
}
|
||||
Resource usersResource = authz.getStoreFactory().getResourceStore().create("Users", resourceServer, resourceServer.getClientId());
|
||||
Set<Scope> scopeset = new HashSet<>();
|
||||
scopeset.add(manageScope);
|
||||
usersResource.updateScopes(scopeset);
|
||||
addScopePermission(authz, resourceServer, "Users.manage.permission", usersResource, manageScope, manageUsersPolicy);
|
||||
}
|
||||
|
||||
private static Policy addScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope, Policy policy) {
|
||||
ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
|
||||
|
||||
representation.setName(name);
|
||||
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||
representation.setLogic(Logic.POSITIVE);
|
||||
representation.addResource(resource.getName());
|
||||
representation.addScope(scope.getName());
|
||||
representation.addPolicy(policy.getName());
|
||||
|
||||
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||
}
|
||||
|
||||
private static Resource createRoleResource(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
|
||||
String roleName = getRoleResourceName(role);
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().create(roleName, resourceServer, resourceServer.getClientId());
|
||||
resource.setType("Role");
|
||||
return resource;
|
||||
}
|
||||
|
||||
private static String getRoleResourceName(RoleModel role) {
|
||||
String roleName = "realm";
|
||||
if (role.getContainer() instanceof ClientModel) {
|
||||
ClientModel client = (ClientModel)role.getContainer();
|
||||
roleName = client.getClientId();
|
||||
}
|
||||
roleName = "role.resource." + roleName + "." + role.getName();
|
||||
return roleName;
|
||||
}
|
||||
|
||||
|
||||
private static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
|
||||
String roleName = "realm";
|
||||
if (role.getContainer() instanceof ClientModel) {
|
||||
ClientModel client = (ClientModel) role.getContainer();
|
||||
roleName = client.getClientId() ;
|
||||
}
|
||||
roleName = "role.policy." + roleName + "." + role.getName();
|
||||
PolicyRepresentation representation = new PolicyRepresentation();
|
||||
|
||||
representation.setName(roleName);
|
||||
representation.setType("role");
|
||||
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||
representation.setLogic(Logic.POSITIVE);
|
||||
String roleValues = "[{\"id\":\"" + role.getId() + "\",\"required\": true}]";
|
||||
Map<String, String> config = new HashMap<>();
|
||||
config.put("roles", roleValues);
|
||||
representation.setConfig(config);
|
||||
|
||||
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||
}
|
||||
|
||||
public static void setupUsers(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
UserModel admin = session.users().addUser(realm, "admin");
|
||||
admin.grantRole(client.getRole(AdminRoles.REALM_ADMIN));
|
||||
UserModel manageUserOnlyUser = session.users().addUser(realm, "manage-user");
|
||||
RoleModel manageUsersRole = client.getRole(AdminRoles.MANAGE_USERS);
|
||||
manageUserOnlyUser.grantRole(manageUsersRole);
|
||||
UserModel manageRealmUser = session.users().addUser(realm, "manage-realm");
|
||||
manageRealmUser.grantRole(manageUsersRole);
|
||||
RoleModel manageRealmRole = client.getRole(AdminRoles.MANAGE_REALM);
|
||||
manageRealmUser.grantRole(manageRealmRole);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUI() throws Exception {
|
||||
testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
|
||||
testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
|
||||
//Thread.sleep(1000000000);
|
||||
}
|
||||
|
||||
public static void evaluateAdminHasManageRealmPermissions(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
UserModel admin = session.users().getUserByUsername("admin", realm);
|
||||
|
||||
AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
|
||||
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||
|
||||
RoleModel manageRealmRole = client.getRole(AdminRoles.MANAGE_REALM);
|
||||
Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(manageRealmRole), resourceServer.getId());
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluation() throws Exception {
|
||||
testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
|
||||
testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
|
||||
|
||||
RealmResource realm = adminClient.realm(TEST);
|
||||
String resourceServerId = realm.clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0).getId();
|
||||
UserRepresentation admin = realm.users().search("admin").get(0);
|
||||
UserRepresentation manageUser = realm.users().search("manage-user").get(0);
|
||||
UserRepresentation manageRealm = realm.users().search("manage-realm").get(0);
|
||||
|
||||
PolicyEvaluationRequest request = new PolicyEvaluationRequest();
|
||||
request.setUserId(admin.getId());
|
||||
request.setClientId(resourceServerId);
|
||||
request.addResource("role.resource." + Constants.REALM_MANAGEMENT_CLIENT_ID + "." + AdminRoles.MANAGE_REALM,
|
||||
"map-role");
|
||||
PolicyEvaluationResponse result = realm.clients().get(resourceServerId).authorization().policies().evaluate(request);
|
||||
Assert.assertEquals(result.getStatus(), DecisionEffect.PERMIT);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,705 @@
|
|||
/*
|
||||
* 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.testsuite.admin;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.AuthorizationProviderFactory;
|
||||
import org.keycloak.authorization.model.Resource;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
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.ResourceServer;
|
||||
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.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.util.AdminClientUtil;
|
||||
|
||||
import javax.ws.rs.ClientErrorException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
//@Ignore
|
||||
public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
|
||||
|
||||
public static final String CLIENT_NAME = "application";
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation testRealmRep = new RealmRepresentation();
|
||||
testRealmRep.setId(TEST);
|
||||
testRealmRep.setRealm(TEST);
|
||||
testRealmRep.setEnabled(true);
|
||||
testRealms.add(testRealmRep);
|
||||
}
|
||||
public static void setupDemo(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
ClientModel client = realm.addClient("sales-pipeline-application");
|
||||
RoleModel clientAdmin = client.addRole("admin");
|
||||
client.addRole("leader-creator");
|
||||
client.addRole("viewLeads");
|
||||
ClientModel client2 = realm.addClient("market-analysis-application");
|
||||
RoleModel client2Admin = client2.addRole("admin");
|
||||
client2.addRole("market-manager");
|
||||
client2.addRole("viewMarkets");
|
||||
GroupModel sales = realm.createGroup("sales");
|
||||
RoleModel salesAppsAdminRole = realm.addRole("sales-apps-admin");
|
||||
salesAppsAdminRole.addCompositeRole(clientAdmin);
|
||||
salesAppsAdminRole.addCompositeRole(client2Admin);
|
||||
ClientModel realmManagementClient = realm.getClientByClientId("realm-management");
|
||||
RoleModel queryClient = realmManagementClient.getRole(AdminRoles.QUERY_CLIENTS);
|
||||
|
||||
|
||||
UserModel admin = session.users().addUser(realm, "salesManager");
|
||||
admin.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
|
||||
admin = session.users().addUser(realm, "sales-group-admin");
|
||||
admin.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
|
||||
admin = session.users().addUser(realm, "sales-it");
|
||||
admin.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
|
||||
admin = session.users().addUser(realm, "sales-pipeline-admin");
|
||||
admin.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
|
||||
admin = session.users().addUser(realm, "client-admin");
|
||||
admin.setEnabled(true);
|
||||
admin.grantRole(queryClient);
|
||||
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
|
||||
|
||||
UserModel user = session.users().addUser(realm, "salesman");
|
||||
user.setEnabled(true);
|
||||
user.joinGroup(sales);
|
||||
|
||||
user = session.users().addUser(realm, "saleswoman");
|
||||
user.setEnabled(true);
|
||||
|
||||
}
|
||||
|
||||
public static void setupPolices(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
RoleModel realmRole = realm.addRole("realm-role");
|
||||
RoleModel realmRole2 = realm.addRole("realm-role2");
|
||||
ClientModel client1 = realm.addClient(CLIENT_NAME);
|
||||
ClientTemplateModel template = realm.addClientTemplate("template");
|
||||
client1.setFullScopeAllowed(false);
|
||||
RoleModel client1Role = client1.addRole("client-role");
|
||||
GroupModel group = realm.createGroup("top");
|
||||
|
||||
RoleModel mapperRole = realm.addRole("mapper");
|
||||
RoleModel managerRole = realm.addRole("manager");
|
||||
RoleModel compositeRole = realm.addRole("composite-role");
|
||||
compositeRole.addCompositeRole(mapperRole);
|
||||
compositeRole.addCompositeRole(managerRole);
|
||||
|
||||
// realm-role and application.client-role will have a role policy associated with their map-role permission
|
||||
{
|
||||
permissions.roles().setPermissionsEnabled(client1Role, true);
|
||||
Policy mapRolePermission = permissions.roles().mapRolePermission(client1Role);
|
||||
ResourceServer server = permissions.roles().resourceServer(client1Role);
|
||||
Policy mapperPolicy = permissions.roles().rolePolicy(server, mapperRole);
|
||||
mapRolePermission.addAssociatedPolicy(mapperPolicy);
|
||||
}
|
||||
|
||||
{
|
||||
permissions.roles().setPermissionsEnabled(realmRole, true);
|
||||
Policy mapRolePermission = permissions.roles().mapRolePermission(realmRole);
|
||||
ResourceServer server = permissions.roles().resourceServer(realmRole);
|
||||
Policy mapperPolicy = permissions.roles().rolePolicy(server, mapperRole);
|
||||
mapRolePermission.addAssociatedPolicy(mapperPolicy);
|
||||
}
|
||||
|
||||
// realmRole2 will have an empty map-role policy
|
||||
{
|
||||
permissions.roles().setPermissionsEnabled(realmRole2, true);
|
||||
}
|
||||
|
||||
// setup Users manage policies
|
||||
{
|
||||
permissions.users().setPermissionsEnabled(true);
|
||||
ResourceServer server = permissions.realmResourceServer();
|
||||
Policy managerPolicy = permissions.roles().rolePolicy(server, managerRole);
|
||||
Policy permission = permissions.users().managePermission();
|
||||
permission.addAssociatedPolicy(managerPolicy);
|
||||
permission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
|
||||
}
|
||||
{
|
||||
permissions.groups().setPermissionsEnabled(group, true);
|
||||
}
|
||||
{
|
||||
permissions.clients().setPermissionsEnabled(client1, true);
|
||||
}
|
||||
// setup Users impersonate policy
|
||||
{
|
||||
ClientModel realmManagementClient = realm.getClientByClientId("realm-management");
|
||||
RoleModel adminRole = realmManagementClient.getRole(AdminRoles.REALM_ADMIN);
|
||||
permissions.users().setPermissionsEnabled(true);
|
||||
ResourceServer server = permissions.realmResourceServer();
|
||||
Policy adminPolicy = permissions.roles().rolePolicy(server, adminRole);
|
||||
adminPolicy.setLogic(Logic.NEGATIVE);
|
||||
Policy permission = permissions.users().userImpersonatedPermission();
|
||||
permission.addAssociatedPolicy(adminPolicy);
|
||||
permission.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void setupUsers(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
ClientModel client = realm.getClientByClientId(CLIENT_NAME);
|
||||
RoleModel realmRole = realm.getRole("realm-role");
|
||||
RoleModel realmRole2 = realm.getRole("realm-role2");
|
||||
RoleModel clientRole = client.getRole("client-role");
|
||||
RoleModel mapperRole = realm.getRole("mapper");
|
||||
RoleModel managerRole = realm.getRole("manager");
|
||||
RoleModel compositeRole = realm.getRole("composite-role");
|
||||
ClientModel realmManagementClient = realm.getClientByClientId("realm-management");
|
||||
RoleModel adminRole = realmManagementClient.getRole(AdminRoles.REALM_ADMIN);
|
||||
RoleModel queryGroupsRole = realmManagementClient.getRole(AdminRoles.QUERY_GROUPS);
|
||||
RoleModel queryUsersRole = realmManagementClient.getRole(AdminRoles.QUERY_USERS);
|
||||
RoleModel queryClientsRole = realmManagementClient.getRole(AdminRoles.QUERY_CLIENTS);
|
||||
|
||||
UserModel nomapAdmin = session.users().addUser(realm, "nomap-admin");
|
||||
nomapAdmin.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, nomapAdmin, UserCredentialModel.password("password"));
|
||||
nomapAdmin.grantRole(adminRole);
|
||||
|
||||
UserModel anotherAdmin = session.users().addUser(realm, "anotherAdmin");
|
||||
anotherAdmin.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, anotherAdmin, UserCredentialModel.password("password"));
|
||||
anotherAdmin.grantRole(adminRole);
|
||||
|
||||
UserModel authorizedUser = session.users().addUser(realm, "authorized");
|
||||
authorizedUser.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, authorizedUser, UserCredentialModel.password("password"));
|
||||
authorizedUser.grantRole(mapperRole);
|
||||
authorizedUser.grantRole(managerRole);
|
||||
|
||||
UserModel authorizedComposite = session.users().addUser(realm, "authorizedComposite");
|
||||
authorizedComposite.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, authorizedComposite, UserCredentialModel.password("password"));
|
||||
authorizedComposite.grantRole(compositeRole);
|
||||
|
||||
UserModel unauthorizedUser = session.users().addUser(realm, "unauthorized");
|
||||
unauthorizedUser.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, unauthorizedUser, UserCredentialModel.password("password"));
|
||||
|
||||
UserModel unauthorizedMapper = session.users().addUser(realm, "unauthorizedMapper");
|
||||
unauthorizedMapper.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, unauthorizedMapper, UserCredentialModel.password("password"));
|
||||
unauthorizedMapper.grantRole(managerRole);
|
||||
|
||||
UserModel user1 = session.users().addUser(realm, "user1");
|
||||
user1.setEnabled(true);
|
||||
|
||||
// group management
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
|
||||
GroupModel group = KeycloakModelUtils.findGroupByPath(realm, "top");
|
||||
UserModel groupMember = session.users().addUser(realm, "groupMember");
|
||||
groupMember.joinGroup(group);
|
||||
groupMember.setEnabled(true);
|
||||
UserModel groupManager = session.users().addUser(realm, "groupManager");
|
||||
groupManager.grantRole(queryGroupsRole);
|
||||
groupManager.grantRole(queryUsersRole);
|
||||
groupManager.setEnabled(true);
|
||||
groupManager.grantRole(mapperRole);
|
||||
session.userCredentialManager().updateCredential(realm, groupManager, UserCredentialModel.password("password"));
|
||||
|
||||
UserModel groupManagerNoMapper = session.users().addUser(realm, "noMapperGroupManager");
|
||||
groupManagerNoMapper.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, groupManagerNoMapper, UserCredentialModel.password("password"));
|
||||
groupManagerNoMapper.grantRole(queryGroupsRole);
|
||||
groupManagerNoMapper.grantRole(queryUsersRole);
|
||||
|
||||
UserPolicyRepresentation groupManagerRep = new UserPolicyRepresentation();
|
||||
groupManagerRep.setName("groupManagers");
|
||||
groupManagerRep.addUser("groupManager");
|
||||
groupManagerRep.addUser("noMapperGroupManager");
|
||||
ResourceServer server = permissions.realmResourceServer();
|
||||
Policy groupManagerPolicy = permissions.authz().getStoreFactory().getPolicyStore().create(groupManagerRep, server);
|
||||
Policy groupManagerPermission = permissions.groups().manageMembersPermission(group);
|
||||
groupManagerPermission.addAssociatedPolicy(groupManagerPolicy);
|
||||
permissions.groups().viewPermission(group).addAssociatedPolicy(groupManagerPolicy);
|
||||
|
||||
UserModel clientMapper = session.users().addUser(realm, "clientMapper");
|
||||
clientMapper.setEnabled(true);
|
||||
clientMapper.grantRole(managerRole);
|
||||
clientMapper.grantRole(queryUsersRole);
|
||||
session.userCredentialManager().updateCredential(realm, clientMapper, UserCredentialModel.password("password"));
|
||||
Policy clientMapperPolicy = permissions.clients().mapRolesPermission(client);
|
||||
UserPolicyRepresentation userRep = new UserPolicyRepresentation();
|
||||
userRep.setName("userClientMapper");
|
||||
userRep.addUser("clientMapper");
|
||||
Policy userPolicy = permissions.authz().getStoreFactory().getPolicyStore().create(userRep, permissions.clients().resourceServer(client));
|
||||
clientMapperPolicy.addAssociatedPolicy(userPolicy);
|
||||
|
||||
UserModel clientManager = session.users().addUser(realm, "clientManager");
|
||||
clientManager.setEnabled(true);
|
||||
clientManager.grantRole(queryClientsRole);
|
||||
session.userCredentialManager().updateCredential(realm, clientManager, UserCredentialModel.password("password"));
|
||||
|
||||
Policy clientManagerPolicy = permissions.clients().managePermission(client);
|
||||
userRep = new UserPolicyRepresentation();
|
||||
userRep.setName("clientManager");
|
||||
userRep.addUser("clientManager");
|
||||
userPolicy = permissions.authz().getStoreFactory().getPolicyStore().create(userRep, permissions.clients().resourceServer(client));
|
||||
clientManagerPolicy.addAssociatedPolicy(userPolicy);
|
||||
|
||||
|
||||
UserModel clientConfigurer = session.users().addUser(realm, "clientConfigurer");
|
||||
clientConfigurer.setEnabled(true);
|
||||
clientConfigurer.grantRole(queryClientsRole);
|
||||
session.userCredentialManager().updateCredential(realm, clientConfigurer, UserCredentialModel.password("password"));
|
||||
|
||||
Policy clientConfigurePolicy = permissions.clients().configurePermission(client);
|
||||
userRep = new UserPolicyRepresentation();
|
||||
userRep.setName("clientConfigure");
|
||||
userRep.addUser("clientConfigurer");
|
||||
userPolicy = permissions.authz().getStoreFactory().getPolicyStore().create(userRep, permissions.clients().resourceServer(client));
|
||||
clientConfigurePolicy.addAssociatedPolicy(userPolicy);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void evaluateLocally(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
RoleModel realmRole = realm.getRole("realm-role");
|
||||
RoleModel realmRole2 = realm.getRole("realm-role2");
|
||||
ClientModel client = realm.getClientByClientId(CLIENT_NAME);
|
||||
RoleModel clientRole = client.getRole("client-role");
|
||||
|
||||
// test authorized
|
||||
{
|
||||
UserModel user = session.users().getUserByUsername("authorized", realm);
|
||||
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
|
||||
Assert.assertTrue(permissionsForAdmin.users().canManage());
|
||||
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
|
||||
}
|
||||
// test composite role
|
||||
{
|
||||
UserModel user = session.users().getUserByUsername("authorizedComposite", realm);
|
||||
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
|
||||
Assert.assertTrue(permissionsForAdmin.users().canManage());
|
||||
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
|
||||
}
|
||||
|
||||
// test unauthorized
|
||||
{
|
||||
UserModel user = session.users().getUserByUsername("unauthorized", realm);
|
||||
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
|
||||
Assert.assertFalse(permissionsForAdmin.users().canManage());
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole));
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||
}
|
||||
// test unauthorized mapper
|
||||
{
|
||||
UserModel user = session.users().getUserByUsername("unauthorizedMapper", realm);
|
||||
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
|
||||
Assert.assertTrue(permissionsForAdmin.users().canManage());
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole));
|
||||
// will result to true because realmRole2 does not have any policies attached to this permission
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||
}
|
||||
// test group management
|
||||
{
|
||||
UserModel admin = session.users().getUserByUsername("groupManager", realm);
|
||||
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, admin);
|
||||
UserModel user = session.users().getUserByUsername("authorized", realm);
|
||||
Assert.assertFalse(permissionsForAdmin.users().canManage(user));
|
||||
Assert.assertFalse(permissionsForAdmin.users().canView(user));
|
||||
UserModel member = session.users().getUserByUsername("groupMember", realm);
|
||||
Assert.assertTrue(permissionsForAdmin.users().canManage(member));
|
||||
Assert.assertTrue(permissionsForAdmin.users().canView(member));
|
||||
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
|
||||
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||
|
||||
}
|
||||
// test client.mapRoles
|
||||
{
|
||||
UserModel admin = session.users().getUserByUsername("clientMapper", realm);
|
||||
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, admin);
|
||||
UserModel user = session.users().getUserByUsername("authorized", realm);
|
||||
Assert.assertTrue(permissionsForAdmin.users().canManage(user));
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
|
||||
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
|
||||
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected boolean isImportAfterEachMethod() {
|
||||
return true;
|
||||
}
|
||||
//@Test
|
||||
public void testDemo() throws Exception {
|
||||
testingClient.server().run(FineGrainAdminUnitTest::setupDemo);
|
||||
Thread.sleep(1000000000);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEvaluationLocal() throws Exception {
|
||||
testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
|
||||
testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
|
||||
testingClient.server().run(FineGrainAdminUnitTest::evaluateLocally);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestEvaluation() throws Exception {
|
||||
testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
|
||||
testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
|
||||
|
||||
UserRepresentation user1 = adminClient.realm(TEST).users().search("user1").get(0);
|
||||
UserRepresentation anotherAdmin = adminClient.realm(TEST).users().search("anotherAdmin").get(0);
|
||||
UserRepresentation groupMember = adminClient.realm(TEST).users().search("groupMember").get(0);
|
||||
RoleRepresentation realmRole = adminClient.realm(TEST).roles().get("realm-role").toRepresentation();
|
||||
List<RoleRepresentation> realmRoleSet = new LinkedList<>();
|
||||
realmRoleSet.add(realmRole);
|
||||
RoleRepresentation realmRole2 = adminClient.realm(TEST).roles().get("realm-role2").toRepresentation();
|
||||
List<RoleRepresentation> realmRole2Set = new LinkedList<>();
|
||||
realmRole2Set.add(realmRole2);
|
||||
ClientRepresentation client = adminClient.realm(TEST).clients().findByClientId(CLIENT_NAME).get(0);
|
||||
ClientTemplateRepresentation template = adminClient.realm(TEST).clientTemplates().findAll().get(0);
|
||||
RoleRepresentation clientRole = adminClient.realm(TEST).clients().get(client.getId()).roles().get("client-role").toRepresentation();
|
||||
List<RoleRepresentation> clientRoleSet = new LinkedList<>();
|
||||
clientRoleSet.add(clientRole);
|
||||
|
||||
// test configure client
|
||||
{
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "clientConfigurer", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
client.setAdminUrl("http://nowhere");
|
||||
realmClient.realm(TEST).clients().get(client.getId()).update(client);
|
||||
client.setFullScopeAllowed(true);
|
||||
try {
|
||||
realmClient.realm(TEST).clients().get(client.getId()).update(client);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
client.setFullScopeAllowed(false);
|
||||
realmClient.realm(TEST).clients().get(client.getId()).update(client);
|
||||
|
||||
client.setClientTemplate(template.getName());
|
||||
try {
|
||||
realmClient.realm(TEST).clients().get(client.getId()).update(client);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
client.setClientTemplate(null);
|
||||
realmClient.realm(TEST).clients().get(client.getId()).update(client);
|
||||
|
||||
try {
|
||||
realmClient.realm(TEST).clients().get(client.getId()).getScopeMappings().realmLevel().add(realmRoleSet);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// test illegal impersonation
|
||||
{
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "nomap-admin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
realmClient.realm(TEST).users().get(user1.getId()).impersonate();
|
||||
realmClient.close(); // just in case of cookie settings
|
||||
realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "nomap-admin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(anotherAdmin.getId()).impersonate();
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "authorized", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
|
||||
List<RoleRepresentation> roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
|
||||
Assert.assertTrue(roles.stream().anyMatch((r) -> {
|
||||
return r.getName().equals("realm-role");
|
||||
}));
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().remove(realmRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
|
||||
Assert.assertTrue(roles.stream().noneMatch((r) -> {
|
||||
return r.getName().equals("realm-role");
|
||||
}));
|
||||
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.stream().anyMatch((r) -> {
|
||||
return r.getName().equals("client-role");
|
||||
}));
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.stream().noneMatch((r) -> {
|
||||
return r.getName().equals("client-role");
|
||||
}));
|
||||
realmClient.close();
|
||||
}
|
||||
|
||||
{
|
||||
Keycloak realmClient= AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "authorizedComposite", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
|
||||
List<RoleRepresentation> roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
|
||||
Assert.assertTrue(roles.stream().anyMatch((r) -> {
|
||||
return r.getName().equals("realm-role");
|
||||
}));
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().remove(realmRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
|
||||
Assert.assertTrue(roles.stream().noneMatch((r) -> {
|
||||
return r.getName().equals("realm-role");
|
||||
}));
|
||||
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.stream().anyMatch((r) -> {
|
||||
return r.getName().equals("client-role");
|
||||
}));
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.stream().noneMatch((r) -> {
|
||||
return r.getName().equals("client-role");
|
||||
}));
|
||||
}
|
||||
{
|
||||
Keycloak realmClient= AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "unauthorized", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
}
|
||||
{
|
||||
Keycloak realmClient= AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "unauthorizedMapper", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "groupManager", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
List<RoleRepresentation> roles = null;
|
||||
realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
|
||||
roles = realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.stream().anyMatch((r) -> {
|
||||
return r.getName().equals("client-role");
|
||||
}));
|
||||
realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
|
||||
|
||||
roles = realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().listAvailable();
|
||||
Assert.assertEquals(roles.size(), 1);
|
||||
realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().add(realmRoleSet);
|
||||
realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().remove(realmRoleSet);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().add(realmRole2Set);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// test client.mapRoles
|
||||
{
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "clientMapper", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
List<RoleRepresentation> roles = null;
|
||||
roles = realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.isEmpty());
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
|
||||
roles = realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.stream().anyMatch((r) -> {
|
||||
return r.getName().equals("client-role");
|
||||
}));
|
||||
roles = realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAvailable();
|
||||
Assert.assertTrue(roles.isEmpty());
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMasterRealm() throws Exception {
|
||||
// test that master realm can still perform operations when policies are in place
|
||||
//
|
||||
testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
|
||||
testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
|
||||
|
||||
UserRepresentation user1 = adminClient.realm(TEST).users().search("user1").get(0);
|
||||
RoleRepresentation realmRole = adminClient.realm(TEST).roles().get("realm-role").toRepresentation();
|
||||
List<RoleRepresentation> realmRoleSet = new LinkedList<>();
|
||||
realmRoleSet.add(realmRole);
|
||||
RoleRepresentation realmRole2 = adminClient.realm(TEST).roles().get("realm-role2").toRepresentation();
|
||||
List<RoleRepresentation> realmRole2Set = new LinkedList<>();
|
||||
realmRole2Set.add(realmRole);
|
||||
ClientRepresentation client = adminClient.realm(TEST).clients().findByClientId(CLIENT_NAME).get(0);
|
||||
RoleRepresentation clientRole = adminClient.realm(TEST).clients().get(client.getId()).roles().get("client-role").toRepresentation();
|
||||
List<RoleRepresentation> clientRoleSet = new LinkedList<>();
|
||||
clientRoleSet.add(clientRole);
|
||||
|
||||
|
||||
{
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting());
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
|
||||
List<RoleRepresentation> roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
|
||||
Assert.assertTrue(roles.stream().anyMatch((r) -> {
|
||||
return r.getName().equals("realm-role");
|
||||
}));
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().remove(realmRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
|
||||
Assert.assertTrue(roles.stream().noneMatch((r) -> {
|
||||
return r.getName().equals("realm-role");
|
||||
}));
|
||||
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.stream().anyMatch((r) -> {
|
||||
return r.getName().equals("client-role");
|
||||
}));
|
||||
realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
|
||||
roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
|
||||
Assert.assertTrue(roles.stream().noneMatch((r) -> {
|
||||
return r.getName().equals("client-role");
|
||||
}));
|
||||
realmClient.close();
|
||||
}
|
||||
|
||||
}
|
||||
// testRestEvaluationMasterRealm
|
||||
// testRestEvaluationMasterAdminTestRealm
|
||||
|
||||
// test role deletion that it cleans up authz objects
|
||||
public static void setupDeleteTest(KeycloakSession session ) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
RoleModel removedRole = realm.addRole("removedRole");
|
||||
ClientModel client = realm.addClient("removedClient");
|
||||
RoleModel removedClientRole = client.addRole("removedClientRole");
|
||||
GroupModel removedGroup = realm.createGroup("removedGroup");
|
||||
AdminPermissionManagement management = AdminPermissions.management(session, realm);
|
||||
management.roles().setPermissionsEnabled(removedRole, true);
|
||||
management.roles().setPermissionsEnabled(removedClientRole, true);
|
||||
management.groups().setPermissionsEnabled(removedGroup, true);
|
||||
management.clients().setPermissionsEnabled(client, true);
|
||||
}
|
||||
|
||||
public static void invokeDelete(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
AdminPermissionManagement management = AdminPermissions.management(session, realm);
|
||||
List<Resource> byResourceServer = management.authz().getStoreFactory().getResourceStore().findByResourceServer(management.realmResourceServer().getId());
|
||||
Assert.assertEquals(4, byResourceServer.size());
|
||||
RoleModel removedRole = realm.getRole("removedRole");
|
||||
realm.removeRole(removedRole);
|
||||
ClientModel client = realm.getClientByClientId("removedClient");
|
||||
RoleModel removedClientRole = client.getRole("removedClientRole");
|
||||
client.removeRole(removedClientRole);
|
||||
GroupModel group = KeycloakModelUtils.findGroupByPath(realm, "removedGroup");
|
||||
realm.removeGroup(group);
|
||||
byResourceServer = management.authz().getStoreFactory().getResourceStore().findByResourceServer(management.realmResourceServer().getId());
|
||||
Assert.assertEquals(1, byResourceServer.size());
|
||||
realm.removeClient(client.getId());
|
||||
byResourceServer = management.authz().getStoreFactory().getResourceStore().findByResourceServer(management.realmResourceServer().getId());
|
||||
Assert.assertEquals(0, byResourceServer.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveCleanup() throws Exception {
|
||||
testingClient.server().run(FineGrainAdminUnitTest::setupDeleteTest);
|
||||
testingClient.server().run(FineGrainAdminUnitTest::invokeDelete);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,648 @@
|
|||
/*
|
||||
* 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.testsuite.admin;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.ImpersonationConstants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.util.AdminClientUtil;
|
||||
|
||||
import javax.ws.rs.ClientErrorException;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class IllegalAdminUpgradeTest extends AbstractKeycloakTest {
|
||||
|
||||
public static final String CLIENT_NAME = "application";
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation testRealmRep = new RealmRepresentation();
|
||||
testRealmRep.setId(TEST);
|
||||
testRealmRep.setRealm(TEST);
|
||||
testRealmRep.setEnabled(true);
|
||||
testRealms.add(testRealmRep);
|
||||
}
|
||||
|
||||
protected boolean isImportAfterEachMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static void setupUsers(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
RealmModel master = session.realms().getRealmByName("master");
|
||||
ClientModel realmAdminClient = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
ClientModel realmMasterAdminClient = realm.getMasterAdminClient();
|
||||
RoleModel realmManageUsers = realmAdminClient.getRole(AdminRoles.MANAGE_USERS);
|
||||
RoleModel masterManageUsers = realmMasterAdminClient.getRole(AdminRoles.MANAGE_USERS);
|
||||
RoleModel masterMasterManageUSers = master.getMasterAdminClient().getRole(AdminRoles.MANAGE_USERS);
|
||||
|
||||
UserModel realmUser = session.users().addUser(realm, "userAdmin");
|
||||
realmUser.grantRole(realmManageUsers);
|
||||
realmUser.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, realmUser, UserCredentialModel.password("password"));
|
||||
|
||||
UserModel masterUser = session.users().addUser(master, "userAdmin");
|
||||
masterUser.grantRole(masterManageUsers);
|
||||
masterUser.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(master, masterUser, UserCredentialModel.password("password"));
|
||||
|
||||
UserModel masterAdmin = session.users().addUser(master, "masterAdmin");
|
||||
masterAdmin.grantRole(masterMasterManageUSers);
|
||||
masterAdmin.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(master, masterAdmin, UserCredentialModel.password("password"));
|
||||
|
||||
UserModel user = session.users().addUser(master, "user");
|
||||
user.grantRole(masterManageUsers);
|
||||
user.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(master, user, UserCredentialModel.password("password"));
|
||||
|
||||
user = session.users().addUser(realm, "user");
|
||||
user.grantRole(realmManageUsers);
|
||||
user.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestEvaluation() throws Exception {
|
||||
testingClient.server().run(IllegalAdminUpgradeTest::setupUsers);
|
||||
|
||||
UserRepresentation realmUserAdmin = adminClient.realm(TEST).users().search("userAdmin").get(0);
|
||||
UserRepresentation masterUserAdmin = adminClient.realm("master").users().search("userAdmin").get(0);
|
||||
UserRepresentation realmUser = adminClient.realm(TEST).users().search("user").get(0);
|
||||
UserRepresentation masterUser = adminClient.realm("master").users().search("user").get(0);
|
||||
|
||||
ClientRepresentation realmAdminClient = adminClient.realm(TEST).clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0);
|
||||
RoleRepresentation realmManageAuthorization = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_AUTHORIZATION).toRepresentation();
|
||||
RoleRepresentation realmViewAuthorization = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_AUTHORIZATION).toRepresentation();
|
||||
RoleRepresentation realmManageClients = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_CLIENTS).toRepresentation();
|
||||
RoleRepresentation realmViewClients = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_CLIENTS).toRepresentation();
|
||||
RoleRepresentation realmManageEvents = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_EVENTS).toRepresentation();
|
||||
RoleRepresentation realmViewEvents = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_EVENTS).toRepresentation();
|
||||
RoleRepresentation realmManageIdentityProviders = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_IDENTITY_PROVIDERS).toRepresentation();
|
||||
RoleRepresentation realmViewIdentityProviders = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_IDENTITY_PROVIDERS).toRepresentation();
|
||||
RoleRepresentation realmManageRealm = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_REALM).toRepresentation();
|
||||
RoleRepresentation realmViewRealm = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_REALM).toRepresentation();
|
||||
RoleRepresentation realmImpersonate = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(ImpersonationConstants.IMPERSONATION_ROLE).toRepresentation();
|
||||
RoleRepresentation realmManageUsers = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_USERS).toRepresentation();
|
||||
RoleRepresentation realmViewUsers = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_USERS).toRepresentation();
|
||||
RoleRepresentation realmQueryUsers = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.QUERY_USERS).toRepresentation();
|
||||
RoleRepresentation realmQueryClients = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.QUERY_CLIENTS).toRepresentation();
|
||||
RoleRepresentation realmQueryGroups = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.QUERY_GROUPS).toRepresentation();
|
||||
|
||||
ClientRepresentation masterClient = adminClient.realm("master").clients().findByClientId(TEST + "-realm").get(0);
|
||||
RoleRepresentation masterManageAuthorization = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_AUTHORIZATION).toRepresentation();
|
||||
RoleRepresentation masterViewAuthorization = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_AUTHORIZATION).toRepresentation();
|
||||
RoleRepresentation masterManageClients = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_CLIENTS).toRepresentation();
|
||||
RoleRepresentation masterViewClients = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_CLIENTS).toRepresentation();
|
||||
RoleRepresentation masterManageEvents = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_EVENTS).toRepresentation();
|
||||
RoleRepresentation masterViewEvents = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_EVENTS).toRepresentation();
|
||||
RoleRepresentation masterManageIdentityProviders = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_IDENTITY_PROVIDERS).toRepresentation();
|
||||
RoleRepresentation masterViewIdentityProviders = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_IDENTITY_PROVIDERS).toRepresentation();
|
||||
RoleRepresentation masterManageRealm = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_REALM).toRepresentation();
|
||||
RoleRepresentation masterViewRealm = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_REALM).toRepresentation();
|
||||
RoleRepresentation masterImpersonate = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(ImpersonationConstants.IMPERSONATION_ROLE).toRepresentation();
|
||||
RoleRepresentation masterManageUsers = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_USERS).toRepresentation();
|
||||
RoleRepresentation masterViewUsers = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_USERS).toRepresentation();
|
||||
RoleRepresentation masterQueryUsers = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.QUERY_USERS).toRepresentation();
|
||||
RoleRepresentation masterQueryClients = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.QUERY_CLIENTS).toRepresentation();
|
||||
RoleRepresentation masterQueryGroups = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.QUERY_GROUPS).toRepresentation();
|
||||
|
||||
List<RoleRepresentation> roles = new LinkedList<>();
|
||||
|
||||
{
|
||||
ClientRepresentation client = realmAdminClient;
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "userAdmin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
roles.clear();
|
||||
roles.add(realmManageAuthorization);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewAuthorization);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageClients);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewClients);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageEvents);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewEvents);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageIdentityProviders);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewIdentityProviders);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageRealm);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewRealm);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmImpersonate);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageUsers);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewUsers);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmQueryUsers);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmQueryGroups);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmQueryClients);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
realmClient.close();
|
||||
}
|
||||
// test master manageUsers only admin can do with master realm admin roles
|
||||
{
|
||||
ClientRepresentation client = masterClient;
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
"master", "masterAdmin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
roles.clear();
|
||||
roles.add(masterManageAuthorization);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewAuthorization);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageClients);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewClients);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageEvents);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewEvents);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageIdentityProviders);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewIdentityProviders);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageRealm);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewRealm);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterImpersonate);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageUsers);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewUsers);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterQueryUsers);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterQueryGroups);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterQueryClients);
|
||||
try {
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
realmClient.close();
|
||||
}
|
||||
// test master admin can add all admin roles in realm
|
||||
{
|
||||
ClientRepresentation client = realmAdminClient;
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient();
|
||||
roles.clear();
|
||||
roles.add(realmManageAuthorization);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewAuthorization);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageClients);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewClients);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageEvents);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewEvents);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageIdentityProviders);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewIdentityProviders);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageRealm);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewRealm);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmImpersonate);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmManageUsers);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmViewUsers);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmQueryUsers);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmQueryGroups);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(realmQueryClients);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
realmClient.close();
|
||||
}
|
||||
// test that "admin" in master realm can assign all roles of master realm realm client admin roles
|
||||
{
|
||||
ClientRepresentation client = masterClient;
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient();
|
||||
roles.clear();
|
||||
roles.add(masterManageAuthorization);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewAuthorization);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageClients);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewClients);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageEvents);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewEvents);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageIdentityProviders);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewIdentityProviders);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageRealm);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewRealm);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterImpersonate);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterManageUsers);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterViewUsers);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterQueryUsers);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterQueryGroups);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
roles.clear();
|
||||
roles.add(masterQueryClients);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
|
||||
realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
|
||||
|
||||
realmClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -22,6 +22,7 @@ import org.junit.Assert;
|
|||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.AuthorizationProviderFactory;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.Resource;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
|
@ -77,7 +78,8 @@ public class PolicyEvaluationCompositeRoleTest extends AbstractKeycloakTest {
|
|||
RoleModel role1 = client.addRole("client-role1");
|
||||
|
||||
|
||||
AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
|
||||
AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
|
||||
AuthorizationProvider authz = factory.create(session, realm);
|
||||
ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
|
||||
Policy policy = createRolePolicy(authz, resourceServer, role1);
|
||||
|
||||
|
|
|
@ -70,4 +70,4 @@ log4j.logger.org.apache.directory.server.core=warn
|
|||
# log4j.logger.org.keycloak.keys.infinispan=trace
|
||||
log4j.logger.org.keycloak.services.clientregistration.policy=debug
|
||||
|
||||
#log4j.logger.org.keycloak.authentication=debug
|
||||
#log4j.logger.org.keycloak.authentication=debug
|
|
@ -1312,9 +1312,35 @@ credential-reset-actions-timeout=Expires In
|
|||
credential-reset-actions-timeout.tooltip=Maximum time before the action permit expires.
|
||||
ldap-mappers=LDAP Mappers
|
||||
create-ldap-mapper=Create LDAP mapper
|
||||
|
||||
|
||||
|
||||
|
||||
map-role-mgmt-scope-description=Policies that decide if an admin can map this role to a user or group
|
||||
manage-authz-users-scope-description=Policies that decide if an admin can manage all users in the realm
|
||||
view-authz-users-scope-description=Policies that decide if an admin can view all users in realm
|
||||
permissions-enabled-role=Permissions Enabled
|
||||
permissions-enabled-role.tooltip=Whether or not to enable fine grain permissions for managing this role. Disabling will delete all current permissions that have been set up.
|
||||
manage-permissions-role.tooltip=Fine grain permissions for managing roles. For example, you can define different policies for who is allowed to map a role.
|
||||
lookup=Lookup
|
||||
manage-permissions-users.tooltip=Fine grain permssions for managing all users in realm. You can define different policies for who is allowed to manage users in the realm.
|
||||
permissions-enabled-users=Permissions Enabled
|
||||
permissions-enabled-users.tooltip=Whether or not to enable fine grain permissions for managing users. Disabling will delete all current permissions that have been set up.
|
||||
manage-permissions-client.tooltip=Fine grain permssions for admins that want to manage this client or apply roles defined by this client.
|
||||
manage-permissions-group.tooltip=Fine grain permssions for admins that want to manage this group or the members of this group.
|
||||
manage-authz-group-scope-description=Policies that decide if an admin can manage this group
|
||||
view-authz-group-scope-description=Policies that decide if an admin can view this group
|
||||
view-members-authz-group-scope-description=Policies that decide if an admin can manage the members of this group
|
||||
manage-authz-client-scope-description=Policies that decide if an admin can manage this client
|
||||
configure-authz-client-scope-description=Reduced management permissions for admin. Cannot set scope, template, or protocol mappers.
|
||||
view-authz-client-scope-description=Policies that decide if an admin can view this client
|
||||
map-roles-authz-client-scope-description=Policies that decide if an admin can map roles defined by this client
|
||||
map-roles-client-scope-authz-client-scope-description=Policies that decide if an admin can apply roles defined by this client to the client scope of another client
|
||||
map-roles-composite-authz-client-scope-description=Policies that decide if an admin can apply roles defined by this client as a composite to another role
|
||||
map-role-authz-role-scope-description=Policies that decide if an admin can map role this role to a user or group
|
||||
map-role-client-scope-authz-role-scope-description=Policies that decide if an admin can apply this role to the client scope of a client
|
||||
map-role-composite-authz-role-scope-description=Policies that decide if an admin can apply this role as a composite to another role
|
||||
manage-group-membership-authz-users-scope-description=Policies that decide if an admin can manage group membership for all users in the realm. This is used in conjunction with specific group policy
|
||||
impersonate-authz-users-scope-description=Policies that decide if admin can impersonate other users
|
||||
map-roles-authz-users-scope-description=Policies that decide if admin can map roles for all users
|
||||
user-impersonated-authz-users-scope-description=Policies that decide which users can be impersonated. These policies are applied to the user being impersonated.
|
||||
manage-membership-authz-group-scope-description=Policies that decide if admin can add or remove users from this group
|
||||
manage-members-authz-group-scope-description=Policies that decide if an admin can manage the members of this group
|
||||
|
||||
|
||||
|
|
|
@ -1398,9 +1398,6 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clients : function(ClientListLoader) {
|
||||
return ClientListLoader();
|
||||
},
|
||||
serverInfo : function(ServerInfoLoader) {
|
||||
return ServerInfoLoader();
|
||||
}
|
||||
|
@ -2358,6 +2355,24 @@ module.directive('kcTabsAuthentication', function () {
|
|||
}
|
||||
});
|
||||
|
||||
module.directive('kcTabsRole', function () {
|
||||
return {
|
||||
scope: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: resourceUrl + '/templates/kc-tabs-role.html'
|
||||
}
|
||||
});
|
||||
|
||||
module.directive('kcTabsClientRole', function () {
|
||||
return {
|
||||
scope: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: resourceUrl + '/templates/kc-tabs-client-role.html'
|
||||
}
|
||||
});
|
||||
|
||||
module.directive('kcTabsUser', function () {
|
||||
return {
|
||||
scope: true,
|
||||
|
@ -2367,6 +2382,15 @@ module.directive('kcTabsUser', function () {
|
|||
}
|
||||
});
|
||||
|
||||
module.directive('kcTabsUsers', function () {
|
||||
return {
|
||||
scope: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: resourceUrl + '/templates/kc-tabs-users.html'
|
||||
}
|
||||
});
|
||||
|
||||
module.directive('kcTabsGroup', function () {
|
||||
return {
|
||||
scope: true,
|
||||
|
|
|
@ -412,7 +412,65 @@ module.config(['$routeProvider', function ($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller: 'ResourceServerPolicyAggregateDetailCtrl'
|
||||
});
|
||||
}).when('/realms/:realm/roles/:role/permissions', {
|
||||
templateUrl : resourceUrl + '/partials/authz/mgmt/realm-role-permissions.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
role : function(RoleLoader) {
|
||||
return RoleLoader();
|
||||
}
|
||||
},
|
||||
controller : 'RealmRolePermissionsCtrl'
|
||||
}).when('/realms/:realm/clients/:client/roles/:role/permissions', {
|
||||
templateUrl : resourceUrl + '/partials/authz/mgmt/client-role-permissions.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
client : function(ClientLoader) {
|
||||
return ClientLoader();
|
||||
},
|
||||
role : function(RoleLoader) {
|
||||
return RoleLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientRolePermissionsCtrl'
|
||||
}).when('/realms/:realm/users-permissions', {
|
||||
templateUrl : resourceUrl + '/partials/authz/mgmt/users-permissions.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
}
|
||||
},
|
||||
controller : 'UsersPermissionsCtrl'
|
||||
})
|
||||
.when('/realms/:realm/clients/:client/permissions', {
|
||||
templateUrl : resourceUrl + '/partials/authz/mgmt/client-permissions.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
client : function(ClientLoader) {
|
||||
return ClientLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPermissionsCtrl'
|
||||
})
|
||||
.when('/realms/:realm/groups/:group/permissions', {
|
||||
templateUrl : resourceUrl + '/partials/authz/mgmt/group-permissions.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
group : function(GroupLoader) {
|
||||
return GroupLoader();
|
||||
}
|
||||
},
|
||||
controller : 'GroupPermissionsCtrl'
|
||||
})
|
||||
;
|
||||
}]);
|
||||
|
||||
module.directive('kcTabsResourceServer', function () {
|
||||
|
|
|
@ -79,72 +79,7 @@ module.controller('ResourceServerDetailCtrl', function($scope, $http, $route, $l
|
|||
});
|
||||
});
|
||||
|
||||
var Resources = {
|
||||
delete: function(ResourceServerResource, realm, client, $scope, AuthzDialog, $location, Notifications, $route) {
|
||||
ResourceServerResource.permissions({
|
||||
realm : realm,
|
||||
client : client.id,
|
||||
rsrid : $scope.resource._id
|
||||
}, function (permissions) {
|
||||
var msg = "";
|
||||
|
||||
if (permissions.length > 0 && !$scope.deleteConsent) {
|
||||
msg = "<p>This resource is referenced in some permissions:</p>";
|
||||
msg += "<ul>";
|
||||
for (i = 0; i < permissions.length; i++) {
|
||||
msg+= "<li><strong>" + permissions[i].name + "</strong></li>";
|
||||
}
|
||||
msg += "</ul>";
|
||||
msg += "<p>If you remove this resource, the permissions above will be affected and will not be associated with this resource anymore.</p>";
|
||||
}
|
||||
|
||||
AuthzDialog.confirmDeleteWithMsg($scope.resource.name, "Resource", msg, function() {
|
||||
ResourceServerResource.delete({realm : realm, client : $scope.client.id, rsrid : $scope.resource._id}, null, function() {
|
||||
$location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource");
|
||||
$route.reload();
|
||||
Notifications.success("The resource has been deleted.");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var Policies = {
|
||||
delete: function(service, realm, client, $scope, AuthzDialog, $location, Notifications, $route, isPermission) {
|
||||
var msg = "";
|
||||
|
||||
service.dependentPolicies({
|
||||
realm : realm,
|
||||
client : client.id,
|
||||
id : $scope.policy.id
|
||||
}, function (dependentPolicies) {
|
||||
if (dependentPolicies.length > 0 && !$scope.deleteConsent) {
|
||||
msg = "<p>This policy is being used by other policies:</p>";
|
||||
msg += "<ul>";
|
||||
for (i = 0; i < dependentPolicies.length; i++) {
|
||||
msg+= "<li><strong>" + dependentPolicies[i].name + "</strong></li>";
|
||||
}
|
||||
msg += "</ul>";
|
||||
msg += "<p>If you remove this policy, the policies above will be affected and will not be associated with this policy anymore.</p>";
|
||||
}
|
||||
|
||||
AuthzDialog.confirmDeleteWithMsg($scope.policy.name, isPermission ? "Permission" : "Policy", msg, function() {
|
||||
service.delete({realm : realm, client : $scope.client.id, id : $scope.policy.id}, null, function() {
|
||||
if (isPermission) {
|
||||
$location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/permission");
|
||||
Notifications.success("The permission has been deleted.");
|
||||
} else {
|
||||
$location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/policy");
|
||||
Notifications.success("The policy has been deleted.");
|
||||
}
|
||||
$route.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerResource, client, AuthzDialog, Notifications) {
|
||||
module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerResource, client) {
|
||||
$scope.realm = realm;
|
||||
$scope.client = client;
|
||||
|
||||
|
@ -236,11 +171,6 @@ module.controller('ResourceServerResourceCtrl', function($scope, $http, $route,
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.delete = function(resource) {
|
||||
$scope.resource = resource;
|
||||
Resources.delete(ResourceServerResource, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route);
|
||||
};
|
||||
});
|
||||
|
||||
module.controller('ResourceServerResourceDetailCtrl', function($scope, $http, $route, $location, realm, ResourceServer, client, ResourceServerResource, ResourceServerScope, AuthzDialog, Notifications) {
|
||||
|
@ -352,7 +282,30 @@ module.controller('ResourceServerResourceDetailCtrl', function($scope, $http, $r
|
|||
}
|
||||
|
||||
$scope.remove = function() {
|
||||
Resources.delete(ResourceServerResource, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route);
|
||||
ResourceServerResource.permissions({
|
||||
realm : $route.current.params.realm,
|
||||
client : client.id,
|
||||
rsrid : $scope.resource._id
|
||||
}, function (permissions) {
|
||||
var msg = "";
|
||||
|
||||
if (permissions.length > 0 && !$scope.deleteConsent) {
|
||||
msg = "<p>This resource is referenced in some policies:</p>";
|
||||
msg += "<ul>";
|
||||
for (i = 0; i < permissions.length; i++) {
|
||||
msg+= "<li><strong>" + permissions[i].name + "</strong></li>";
|
||||
}
|
||||
msg += "</ul>";
|
||||
msg += "<p>If you remove this resource, the policies above will be affected and will not be associated with this resource anymore.</p>";
|
||||
}
|
||||
|
||||
AuthzDialog.confirmDeleteWithMsg($scope.resource.name, "Resource", msg, function() {
|
||||
ResourceServerResource.delete({realm : realm.realm, client : $scope.client.id, rsrid : $scope.resource._id}, null, function() {
|
||||
$location.url("/realms/" + realm.realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource");
|
||||
Notifications.success("The resource has been deleted.");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$scope.reset = function() {
|
||||
|
@ -385,37 +338,7 @@ module.controller('ResourceServerResourceDetailCtrl', function($scope, $http, $r
|
|||
}
|
||||
});
|
||||
|
||||
var Scopes = {
|
||||
delete: function(ResourceServerScope, realm, client, $scope, AuthzDialog, $location, Notifications, $route) {
|
||||
ResourceServerScope.permissions({
|
||||
realm : realm,
|
||||
client : client.id,
|
||||
id : $scope.scope.id
|
||||
}, function (permissions) {
|
||||
var msg = "";
|
||||
|
||||
if (permissions.length > 0 && !$scope.deleteConsent) {
|
||||
msg = "<p>This scope is referenced in some permissions:</p>";
|
||||
msg += "<ul>";
|
||||
for (i = 0; i < permissions.length; i++) {
|
||||
msg+= "<li><strong>" + permissions[i].name + "</strong></li>";
|
||||
}
|
||||
msg += "</ul>";
|
||||
msg += "<p>If you remove this scope, the permissions above will be affected and will not be associated with this scope anymore.</p>";
|
||||
}
|
||||
|
||||
AuthzDialog.confirmDeleteWithMsg($scope.scope.name, "Scope", msg, function() {
|
||||
ResourceServerScope.delete({realm : realm, client : $scope.client.id, id : $scope.scope.id}, null, function() {
|
||||
$location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/scope");
|
||||
$route.reload();
|
||||
Notifications.success("The scope has been deleted.");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerScope,client, AuthzDialog, Notifications) {
|
||||
module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerScope, client) {
|
||||
$scope.realm = realm;
|
||||
$scope.client = client;
|
||||
|
||||
|
@ -507,11 +430,6 @@ module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $lo
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.delete = function(scope) {
|
||||
$scope.scope = scope;
|
||||
Scopes.delete(ResourceServerScope, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route);
|
||||
};
|
||||
});
|
||||
|
||||
module.controller('ResourceServerScopeDetailCtrl', function($scope, $http, $route, $location, realm, ResourceServer, client, ResourceServerScope, AuthzDialog, Notifications) {
|
||||
|
@ -581,7 +499,30 @@ module.controller('ResourceServerScopeDetailCtrl', function($scope, $http, $rout
|
|||
}
|
||||
|
||||
$scope.remove = function() {
|
||||
Scopes.delete(ResourceServerScope, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route);
|
||||
ResourceServerScope.permissions({
|
||||
realm : $route.current.params.realm,
|
||||
client : client.id,
|
||||
id : $scope.scope.id
|
||||
}, function (permissions) {
|
||||
var msg = "";
|
||||
|
||||
if (permissions.length > 0 && !$scope.deleteConsent) {
|
||||
msg = "<p>This scope is referenced in some policies:</p>";
|
||||
msg += "<ul>";
|
||||
for (i = 0; i < permissions.length; i++) {
|
||||
msg+= "<li><strong>" + permissions[i].name + "</strong></li>";
|
||||
}
|
||||
msg += "</ul>";
|
||||
msg += "<p>If you remove this scope, the policies above will be affected and will not be associated with this scope anymore.</p>";
|
||||
}
|
||||
|
||||
AuthzDialog.confirmDeleteWithMsg($scope.scope.name, "Scope", msg, function() {
|
||||
ResourceServerScope.delete({realm : realm.realm, client : $scope.client.id, id : $scope.scope.id}, null, function() {
|
||||
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/scope");
|
||||
Notifications.success("The scope has been deleted.");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$scope.reset = function() {
|
||||
|
@ -613,7 +554,7 @@ module.controller('ResourceServerScopeDetailCtrl', function($scope, $http, $rout
|
|||
}
|
||||
});
|
||||
|
||||
module.controller('ResourceServerPolicyCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPolicy, PolicyProvider, client, AuthzDialog, Notifications) {
|
||||
module.controller('ResourceServerPolicyCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPolicy, PolicyProvider, client) {
|
||||
$scope.realm = realm;
|
||||
$scope.client = client;
|
||||
$scope.policyProviders = [];
|
||||
|
@ -709,14 +650,9 @@ module.controller('ResourceServerPolicyCtrl', function($scope, $http, $route, $l
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.delete = function(policy) {
|
||||
$scope.policy = policy;
|
||||
Policies.delete(ResourceServerPolicy, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, false);
|
||||
};
|
||||
});
|
||||
|
||||
module.controller('ResourceServerPermissionCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPermission, PolicyProvider, client, AuthzDialog, Notifications) {
|
||||
module.controller('ResourceServerPermissionCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPermission, PolicyProvider, client) {
|
||||
$scope.realm = realm;
|
||||
$scope.client = client;
|
||||
$scope.policyProviders = [];
|
||||
|
@ -811,11 +747,6 @@ module.controller('ResourceServerPermissionCtrl', function($scope, $http, $route
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.delete = function(policy) {
|
||||
$scope.policy = policy;
|
||||
Policies.delete(ResourceServerPermission, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, true);
|
||||
};
|
||||
});
|
||||
|
||||
module.controller('ResourceServerPolicyDroolsDetailCtrl', function($scope, $http, $route, realm, client, PolicyController) {
|
||||
|
@ -1260,19 +1191,17 @@ module.controller('ResourceServerPolicyScopeDetailCtrl', function($scope, $route
|
|||
client : client.id,
|
||||
id : policy.id
|
||||
}, function(policies) {
|
||||
if (policies.length > 0) {
|
||||
$scope.selectedPolicies = [];
|
||||
for (i = 0; i < policies.length; i++) {
|
||||
policies[i].text = policies[i].name;
|
||||
$scope.selectedPolicies.push(policies[i]);
|
||||
}
|
||||
var copy = angular.copy($scope.selectedPolicies);
|
||||
$scope.$watch('selectedPolicies', function() {
|
||||
if (!angular.equals($scope.selectedPolicies, copy)) {
|
||||
$scope.changed = true;
|
||||
}
|
||||
}, true);
|
||||
$scope.selectedPolicies = [];
|
||||
for (i = 0; i < policies.length; i++) {
|
||||
policies[i].text = policies[i].name;
|
||||
$scope.selectedPolicies.push(policies[i]);
|
||||
}
|
||||
var copy = angular.copy($scope.selectedPolicies);
|
||||
$scope.$watch('selectedPolicies', function() {
|
||||
if (!angular.equals($scope.selectedPolicies, copy)) {
|
||||
$scope.changed = true;
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -2169,7 +2098,35 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
|
|||
});
|
||||
|
||||
$scope.remove = function() {
|
||||
Policies.delete(ResourceServerPolicy, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, delegate.isPermission());
|
||||
var msg = "";
|
||||
|
||||
service.dependentPolicies({
|
||||
realm : $route.current.params.realm,
|
||||
client : client.id,
|
||||
id : $scope.policy.id
|
||||
}, function (dependentPolicies) {
|
||||
if (dependentPolicies.length > 0 && !$scope.deleteConsent) {
|
||||
msg = "<p>This policy is being used by other policies:</p>";
|
||||
msg += "<ul>";
|
||||
for (i = 0; i < dependentPolicies.length; i++) {
|
||||
msg+= "<li><strong>" + dependentPolicies[i].name + "</strong></li>";
|
||||
}
|
||||
msg += "</ul>";
|
||||
msg += "<p>If you remove this policy, the policies above will be affected and will not be associated with this policy anymore.</p>";
|
||||
}
|
||||
|
||||
AuthzDialog.confirmDeleteWithMsg($scope.policy.name, "Policy", msg, function() {
|
||||
service.delete({realm : $scope.realm.realm, client : $scope.client.id, id : $scope.policy.id}, null, function() {
|
||||
if (delegate.isPermission()) {
|
||||
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission");
|
||||
Notifications.success("The permission has been deleted.");
|
||||
} else {
|
||||
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy");
|
||||
Notifications.success("The policy has been deleted.");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2204,21 +2161,13 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio
|
|||
$scope.client = client;
|
||||
$scope.clients = clients;
|
||||
$scope.roles = roles;
|
||||
authzRequest = {};
|
||||
authzRequest.resources = [];
|
||||
authzRequest.context = {};
|
||||
authzRequest.context.attributes = {};
|
||||
authzRequest.roleIds = [];
|
||||
$scope.authzRequest = {};
|
||||
$scope.authzRequest.resources = [];
|
||||
$scope.authzRequest.context = {};
|
||||
$scope.authzRequest.context.attributes = {};
|
||||
$scope.authzRequest.roleIds = [];
|
||||
$scope.resultUrl = resourceUrl + '/partials/authz/policy/resource-server-policy-evaluate-result.html';
|
||||
|
||||
$scope.authzRequest = angular.copy(authzRequest);
|
||||
|
||||
$scope.$watch('authzRequest', function() {
|
||||
if (!angular.equals($scope.authzRequest, authzRequest)) {
|
||||
$scope.changed = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
$scope.addContextAttribute = function() {
|
||||
if (!$scope.newContextAttribute.value || $scope.newContextAttribute.value == '') {
|
||||
Notifications.error("You must provide a value to a context attribute.");
|
||||
|
@ -2531,4 +2480,103 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio
|
|||
$scope.authzRequest = angular.copy(authzRequest);
|
||||
$scope.changed = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
getManageClientId = function(realm) {
|
||||
if (realm.realm == masterRealm) {
|
||||
return 'master-realm';
|
||||
} else {
|
||||
return 'realm-management';
|
||||
}
|
||||
}
|
||||
|
||||
module.controller('RealmRolePermissionsCtrl', function($scope, $http, $route, $location, realm, role, RoleManagementPermissions, Client, Notifications) {
|
||||
console.log('RealmRolePermissionsCtrl');
|
||||
$scope.role = role;
|
||||
$scope.realm = realm;
|
||||
RoleManagementPermissions.get({realm: realm.realm, role: role.id}, function(data) {
|
||||
$scope.permissions = data;
|
||||
});
|
||||
Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
|
||||
$scope.realmManagementClientId = data[0].id;
|
||||
});
|
||||
$scope.setEnabled = function() {
|
||||
var param = { enabled: $scope.permissions.enabled};
|
||||
$scope.permissions= RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
module.controller('ClientRolePermissionsCtrl', function($scope, $http, $route, $location, realm, client, role, Client, RoleManagementPermissions, Client, Notifications) {
|
||||
console.log('RealmRolePermissionsCtrl');
|
||||
$scope.client = client;
|
||||
$scope.role = role;
|
||||
$scope.realm = realm;
|
||||
RoleManagementPermissions.get({realm: realm.realm, role: role.id}, function(data) {
|
||||
$scope.permissions = data;
|
||||
});
|
||||
Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
|
||||
$scope.realmManagementClientId = data[0].id;
|
||||
});
|
||||
$scope.setEnabled = function() {
|
||||
console.log('perssions enabled: ' + $scope.permissions.enabled);
|
||||
var param = { enabled: $scope.permissions.enabled};
|
||||
$scope.permissions = RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
module.controller('UsersPermissionsCtrl', function($scope, $http, $route, $location, realm, UsersManagementPermissions, Client, Notifications) {
|
||||
console.log('UsersPermissionsCtrl');
|
||||
$scope.realm = realm;
|
||||
UsersManagementPermissions.get({realm: realm.realm}, function(data) {
|
||||
$scope.permissions = data;
|
||||
});
|
||||
Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
|
||||
$scope.realmManagementClientId = data[0].id;
|
||||
});
|
||||
$scope.changeIt = function() {
|
||||
console.log('before permissions.enabled=' + $scope.permissions.enabled);
|
||||
var param = { enabled: $scope.permissions.enabled};
|
||||
$scope.permissions = UsersManagementPermissions.update({realm: realm.realm}, param);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
module.controller('ClientPermissionsCtrl', function($scope, $http, $route, $location, realm, client, Client, ClientManagementPermissions, Notifications) {
|
||||
$scope.client = client;
|
||||
$scope.realm = realm;
|
||||
ClientManagementPermissions.get({realm: realm.realm, client: client.id}, function(data) {
|
||||
$scope.permissions = data;
|
||||
});
|
||||
Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
|
||||
$scope.realmManagementClientId = data[0].id;
|
||||
});
|
||||
$scope.setEnabled = function() {
|
||||
var param = { enabled: $scope.permissions.enabled};
|
||||
$scope.permissions = ClientManagementPermissions.update({realm: realm.realm, client: client.id}, param);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
module.controller('GroupPermissionsCtrl', function($scope, $http, $route, $location, realm, group, GroupManagementPermissions, Client, Notifications) {
|
||||
$scope.group = group;
|
||||
$scope.realm = realm;
|
||||
Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
|
||||
$scope.realmManagementClientId = data[0].id;
|
||||
});
|
||||
GroupManagementPermissions.get({realm: realm.realm, group: group.id}, function(data) {
|
||||
$scope.permissions = data;
|
||||
});
|
||||
$scope.setEnabled = function() {
|
||||
var param = { enabled: $scope.permissions.enabled};
|
||||
$scope.permissions = GroupManagementPermissions.update({realm: realm.realm, group: group.id}, param);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -144,4 +144,50 @@ module.service('AuthzDialog', function($modal) {
|
|||
}
|
||||
|
||||
return dialog;
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('RoleManagementPermissions', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/management/permissions', {
|
||||
realm : '@realm',
|
||||
role : '@role'
|
||||
}, {
|
||||
update: {
|
||||
method: 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('UsersManagementPermissions', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/users-management-permissions', {
|
||||
realm : '@realm'
|
||||
}, {
|
||||
update: {
|
||||
method: 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ClientManagementPermissions', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/clients/:client/management/permissions', {
|
||||
realm : '@realm',
|
||||
client : '@client'
|
||||
}, {
|
||||
update: {
|
||||
method: 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('GroupManagementPermissions', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/groups/:group/management/permissions', {
|
||||
realm : '@realm',
|
||||
group : '@group'
|
||||
}, {
|
||||
update: {
|
||||
method: 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -728,9 +728,9 @@ module.controller('ClientImportCtrl', function($scope, $location, $upload, realm
|
|||
});
|
||||
|
||||
|
||||
module.controller('ClientListCtrl', function($scope, realm, clients, Client, serverInfo, $route, Dialog, Notifications, filterFilter) {
|
||||
module.controller('ClientListCtrl', function($scope, realm, Client, serverInfo, $route, Dialog, Notifications, filterFilter) {
|
||||
$scope.realm = realm;
|
||||
$scope.clients = clients;
|
||||
$scope.clients = Client.query({realm: realm.realm, viewableOnly: true});
|
||||
$scope.currentPage = 1;
|
||||
$scope.currentPageInput = 1;
|
||||
$scope.pageSize = 20;
|
||||
|
@ -1387,6 +1387,7 @@ module.controller('ClientScopeMappingCtrl', function($scope, $http, realm, clien
|
|||
}
|
||||
|
||||
$scope.changeFlag = function() {
|
||||
console.log('changeFlag');
|
||||
Client.update({
|
||||
realm : realm.realm,
|
||||
client : client.id
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue