fine grain tests
This commit is contained in:
parent
c3b44e61d4
commit
f760427c5c
29 changed files with 1160 additions and 362 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,9 @@ import org.keycloak.authorization.model.ResourceServer;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.admin.AdminAuth;
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
@ -47,7 +49,8 @@ public class MgmtPermissions {
|
||||||
public MgmtPermissions(KeycloakSession session, RealmModel realm) {
|
public MgmtPermissions(KeycloakSession session, RealmModel realm) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
|
KeycloakSessionFactory keycloakSessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
AuthorizationProviderFactory factory = (AuthorizationProviderFactory) keycloakSessionFactory.getProviderFactory(AuthorizationProvider.class);
|
||||||
this.authz = factory.create(session, realm);
|
this.authz = factory.create(session, realm);
|
||||||
}
|
}
|
||||||
public MgmtPermissions(KeycloakSession session, RealmModel realm, AdminAuth auth) {
|
public MgmtPermissions(KeycloakSession session, RealmModel realm, AdminAuth auth) {
|
||||||
|
@ -57,10 +60,11 @@ public class MgmtPermissions {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAdminSameRealm() {
|
public boolean isAdminSameRealm() {
|
||||||
return realm.getId().equals(auth.getRealm().getId());
|
return auth == null || realm.getId().equals(auth.getRealm().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public RealmAuth getRealmAuth() {
|
public RealmAuth getRealmAuth() {
|
||||||
|
if (auth == null) return null;
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||||
return new RealmAuth(auth, realm.getMasterAdminClient());
|
return new RealmAuth(auth, realm.getMasterAdminClient());
|
||||||
|
@ -71,7 +75,7 @@ public class MgmtPermissions {
|
||||||
|
|
||||||
public Identity identity() {
|
public Identity identity() {
|
||||||
if (identity != null) return identity;
|
if (identity != null) return identity;
|
||||||
if (auth.getClient().getClientId().equals(Constants.REALM_MANAGEMENT_CLIENT_ID)) {
|
if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)) {
|
||||||
this.identity = new UserModelIdentity(realm, auth.getUser());
|
this.identity = new UserModelIdentity(realm, auth.getUser());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -80,11 +84,17 @@ public class MgmtPermissions {
|
||||||
return this.identity;
|
return this.identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setIdentity(UserModel user) {
|
||||||
|
this.identity = new UserModelIdentity(realm, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public RoleMgmtPermissions roles() {
|
public RoleMgmtPermissions roles() {
|
||||||
return new RoleMgmtPermissions(session, realm, authz, this);
|
return new RoleMgmtPermissions(session, realm, authz, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UsersPermissions users() { return new UsersPermissions(session, realm, authz, this); }
|
||||||
|
|
||||||
public ResourceServer findOrCreateResourceServer(ClientModel client) {
|
public ResourceServer findOrCreateResourceServer(ClientModel client) {
|
||||||
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.keycloak.authorization.permission.ResourcePermission;
|
||||||
import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
|
import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
|
||||||
import org.keycloak.authorization.policy.evaluation.DecisionResult;
|
import org.keycloak.authorization.policy.evaluation.DecisionResult;
|
||||||
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||||
|
import org.keycloak.authorization.store.ResourceStore;
|
||||||
import org.keycloak.authorization.util.Permissions;
|
import org.keycloak.authorization.util.Permissions;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
@ -59,16 +60,7 @@ public class RoleMgmtPermissions {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPermissionsEnabled(RoleModel role) {
|
public boolean isPermissionsEnabled(RoleModel role) {
|
||||||
ClientModel client = getRoleClient(role);
|
return mapRolePermission(role) != null;
|
||||||
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
|
||||||
if (server == null) return false;
|
|
||||||
|
|
||||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
|
|
||||||
if (resource == null) return false;
|
|
||||||
|
|
||||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
|
|
||||||
|
|
||||||
return policy != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPermissionsEnabled(RoleModel role, boolean enable) {
|
public void setPermissionsEnabled(RoleModel role, boolean enable) {
|
||||||
|
@ -79,8 +71,7 @@ public class RoleMgmtPermissions {
|
||||||
}
|
}
|
||||||
createResource(role);
|
createResource(role);
|
||||||
} else {
|
} else {
|
||||||
ClientModel client = getRoleClient(role);
|
ResourceServer server = resourceServer(role);
|
||||||
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
|
||||||
if (server == null) return;
|
if (server == null) return;
|
||||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
|
||||||
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
|
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
|
||||||
|
@ -89,6 +80,44 @@ public class RoleMgmtPermissions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Policy mapRolePermission(RoleModel role) {
|
||||||
|
ResourceServer server = resourceServer(role);
|
||||||
|
if (server == null) return null;
|
||||||
|
|
||||||
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
|
||||||
|
if (resource == null) return null;
|
||||||
|
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
|
||||||
|
return authz.getStoreFactory().getPolicyStore().findById(policy.getId(), server.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource resource(RoleModel role) {
|
||||||
|
ResourceStore resourceStore = authz.getStoreFactory().getResourceStore();
|
||||||
|
ResourceServer server = resourceServer(role);
|
||||||
|
if (server == null) return null;
|
||||||
|
Resource resource = resourceStore.findByName(getRoleResourceName(role), server.getId());
|
||||||
|
if (resource == null) return null;
|
||||||
|
return resourceStore.findById(resource.getId(), server.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceServer resourceServer(RoleModel role) {
|
||||||
|
ClientModel client = getRoleClient(role);
|
||||||
|
return authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is admin allowed to map this role? In Authz terms, does the user have the "map-role" scope for the role's Authz resource?
|
||||||
|
*
|
||||||
|
* This method is hardcoded to return TRUE if any of these conditions are met:
|
||||||
|
* - The admin is from the master realm managing a different realm
|
||||||
|
* - If the Authz objects are not set up correctly for this role (resource server, resource, permission)
|
||||||
|
* - If the role's mapRole permission does not have a policy associated with it.
|
||||||
|
*
|
||||||
|
* Otherwise, it will use the Authz policy engine to resolve this answer.
|
||||||
|
*
|
||||||
|
* @param role
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean canMapRole(RoleModel role) {
|
public boolean canMapRole(RoleModel role) {
|
||||||
if (!root.isAdminSameRealm()) {
|
if (!root.isAdminSameRealm()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -101,22 +130,27 @@ public class RoleMgmtPermissions {
|
||||||
return true; // if no policies applied, just ignore
|
return true; // if no policies applied, just ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RealmModel oldRealm = session.getContext().getRealm();
|
||||||
|
try {
|
||||||
|
session.getContext().setRealm(realm);
|
||||||
|
Identity identity = root.identity();
|
||||||
|
|
||||||
Identity identity = root.identity();
|
EvaluationContext context = new DefaultEvaluationContext(identity, session);
|
||||||
|
DecisionResult decisionCollector = new DecisionResult();
|
||||||
|
Resource roleResource = resource(role);
|
||||||
|
Scope mapRoleScope = getMapRoleScope(resourceServer);
|
||||||
|
|
||||||
EvaluationContext context = new DefaultEvaluationContext(identity, session);
|
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
|
||||||
DecisionResult decisionCollector = new DecisionResult();
|
PermissionEvaluator from = authz.evaluators().from(permissions, context);
|
||||||
Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), resourceServer.getId());
|
from.evaluate(decisionCollector);
|
||||||
Scope mapRoleScope = getMapRoleScope(resourceServer);
|
if (!decisionCollector.completed()) {
|
||||||
|
logger.error("Failed to run map role policy check", decisionCollector.getError());
|
||||||
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
|
return false;
|
||||||
PermissionEvaluator from = authz.evaluators().from(permissions, context);
|
}
|
||||||
from.evaluate(decisionCollector);
|
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
|
||||||
if (!decisionCollector.completed()) {
|
} finally {
|
||||||
logger.error("Failed to run map role policy check", decisionCollector.getError());
|
session.getContext().setRealm(oldRealm);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,12 +164,12 @@ public class RoleMgmtPermissions {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Policy getManageUsersPolicy(ResourceServer server) {
|
public Policy manageUsersPolicy(ResourceServer server) {
|
||||||
RoleModel role = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).getRole(AdminRoles.MANAGE_USERS);
|
RoleModel role = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).getRole(AdminRoles.MANAGE_USERS);
|
||||||
return getRolePolicy(server, role);
|
return rolePolicy(server, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Policy getRolePolicy(ResourceServer server, RoleModel role) {
|
public Policy rolePolicy(ResourceServer server, RoleModel role) {
|
||||||
String policyName = Helper.getRolePolicyName(role);
|
String policyName = Helper.getRolePolicyName(role);
|
||||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(policyName, server.getId());
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(policyName, server.getId());
|
||||||
if (policy != null) return policy;
|
if (policy != null) return policy;
|
||||||
|
|
|
@ -30,14 +30,13 @@ import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
|
||||||
import org.keycloak.authorization.policy.evaluation.DecisionResult;
|
import org.keycloak.authorization.policy.evaluation.DecisionResult;
|
||||||
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||||
import org.keycloak.authorization.util.Permissions;
|
import org.keycloak.authorization.util.Permissions;
|
||||||
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.services.resources.admin.AdminAuth;
|
|
||||||
import org.keycloak.services.resources.admin.RealmAuth;
|
import org.keycloak.services.resources.admin.RealmAuth;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -45,11 +44,16 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Manages default policies for all users.
|
||||||
|
*
|
||||||
|
*
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class UsersPermissions {
|
public class UsersPermissions {
|
||||||
private static final Logger logger = Logger.getLogger(UsersPermissions.class);
|
private static final Logger logger = Logger.getLogger(UsersPermissions.class);
|
||||||
|
public static final String MANAGE_PERMISSION_USERS = "manage.permission.users";
|
||||||
|
public static final String USERS_RESOURCE = "Users";
|
||||||
protected final KeycloakSession session;
|
protected final KeycloakSession session;
|
||||||
protected final RealmModel realm;
|
protected final RealmModel realm;
|
||||||
protected final AuthorizationProvider authz;
|
protected final AuthorizationProvider authz;
|
||||||
|
@ -70,45 +74,44 @@ public class UsersPermissions {
|
||||||
manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
|
manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
|
||||||
|
|
||||||
}
|
}
|
||||||
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||||
if (usersResource == null) {
|
if (usersResource == null) {
|
||||||
usersResource = authz.getStoreFactory().getResourceStore().create("Users", server, server.getClientId());
|
usersResource = authz.getStoreFactory().getResourceStore().create(USERS_RESOURCE, server, server.getClientId());
|
||||||
}
|
}
|
||||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
|
||||||
if (policy == null) {
|
if (policy == null) {
|
||||||
Set<Scope> scopeset = new HashSet<>();
|
Set<Scope> scopeset = new HashSet<>();
|
||||||
scopeset.add(manageScope);
|
scopeset.add(manageScope);
|
||||||
usersResource.updateScopes(scopeset);
|
usersResource.updateScopes(scopeset);
|
||||||
Policy manageUsersPolicy = root.roles().getManageUsersPolicy(server);
|
Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
|
||||||
Helper.addScopePermission(authz, server, "manage.permission.users", usersResource, manageScope, manageUsersPolicy);
|
Helper.addScopePermission(authz, server, MANAGE_PERMISSION_USERS, usersResource, manageScope, manageUsersPolicy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPermissionsEnabled() {
|
public boolean isPermissionsEnabled() {
|
||||||
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
ResourceServer server = resourceServer();
|
||||||
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
|
||||||
if (server == null) return false;
|
if (server == null) return false;
|
||||||
|
|
||||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||||
if (resource == null) return false;
|
if (resource == null) return false;
|
||||||
|
|
||||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
|
||||||
|
|
||||||
return policy != null;
|
return policy != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPermissionsEnabled(RoleModel role, boolean enable) {
|
public void setPermissionsEnabled(boolean enable) {
|
||||||
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
if (enable) {
|
if (enable) {
|
||||||
initialize();
|
initialize();
|
||||||
} else {
|
} else {
|
||||||
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
if (server == null) return;
|
if (server == null) return;
|
||||||
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||||
if (usersResource == null) {
|
if (usersResource == null) {
|
||||||
authz.getStoreFactory().getResourceStore().delete(usersResource.getId());
|
authz.getStoreFactory().getResourceStore().delete(usersResource.getId());
|
||||||
}
|
}
|
||||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
|
||||||
if (policy == null) {
|
if (policy == null) {
|
||||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||||
|
|
||||||
|
@ -117,9 +120,9 @@ public class UsersPermissions {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Resource getUsersResource(ResourceServer server) {
|
private Resource getUsersResource(ResourceServer server) {
|
||||||
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||||
if (usersResource == null) {
|
if (usersResource == null) {
|
||||||
usersResource = authz.getStoreFactory().getResourceStore().create("Users", server, server.getClientId());
|
usersResource = authz.getStoreFactory().getResourceStore().create(USERS_RESOURCE, server, server.getClientId());
|
||||||
}
|
}
|
||||||
return usersResource;
|
return usersResource;
|
||||||
}
|
}
|
||||||
|
@ -138,51 +141,108 @@ public class UsersPermissions {
|
||||||
return root.findOrCreateResourceServer(client);
|
return root.findOrCreateResourceServer(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canManageDefault() {
|
private boolean canManageDefault(UserModel admin) {
|
||||||
RealmAuth auth = root.getRealmAuth();
|
RealmAuth auth = root.getRealmAuth();
|
||||||
auth.init(RealmAuth.Resource.USER);
|
if (auth != null) {
|
||||||
return auth.hasManage();
|
auth.init(RealmAuth.Resource.USER);
|
||||||
|
return auth.hasManage();
|
||||||
|
} else {
|
||||||
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
RoleModel manageUsers = client.getRole(AdminRoles.MANAGE_USERS);
|
||||||
|
return admin.hasRole(manageUsers);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canManage(UserModel user) {
|
public boolean canManage() {
|
||||||
|
if (root.getRealmAuth() == null) {
|
||||||
|
throw new NullPointerException("Realm auth null");
|
||||||
|
}
|
||||||
|
return canManage(root.getRealmAuth().getAuth().getUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource resource() {
|
||||||
|
ResourceServer server = resourceServer();
|
||||||
|
if (server == null) return null;
|
||||||
|
|
||||||
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||||
|
if (resource == null) return null;
|
||||||
|
return authz.getStoreFactory().getResourceStore().findById(resource.getId(), server.getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is admin allowed to manage users? In Authz terms, does the admin have the "map-role" scope for the role's Authz resource?
|
||||||
|
*
|
||||||
|
* This method will follow the old default behavior (does the admin have the manage-users role) if any of these conditions
|
||||||
|
* are met.:
|
||||||
|
* - The admin is from the master realm managing a different realm
|
||||||
|
* - If the Authz objects are not set up correctly for the Users resource in Authz
|
||||||
|
* - The "manage" permission for the Users resource has an empty associatedPolicy list.
|
||||||
|
*
|
||||||
|
* Otherwise, it will use the Authz policy engine to resolve this answer.
|
||||||
|
*
|
||||||
|
* @param admin
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean canManage(UserModel admin) {
|
||||||
if (!root.isAdminSameRealm()) {
|
if (!root.isAdminSameRealm()) {
|
||||||
return canManageDefault();
|
return canManageDefault(admin);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
ResourceServer server = resourceServer();
|
||||||
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
if (server == null) return canManageDefault(admin);
|
||||||
if (server == null) return canManageDefault();
|
|
||||||
|
|
||||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||||
if (resource == null) return canManageDefault();
|
if (resource == null) return canManageDefault(admin);
|
||||||
|
|
||||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
|
||||||
if (policy == null) {
|
if (policy == null) {
|
||||||
return canManageDefault();
|
return canManageDefault(admin);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||||
// if no policies attached to permission then just do default behavior
|
// if no policies attached to permission then just do default behavior
|
||||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||||
return canManageDefault();
|
return canManageDefault(admin);
|
||||||
}
|
}
|
||||||
|
|
||||||
Identity identity = root.identity();
|
RealmModel oldRealm = session.getContext().getRealm();
|
||||||
EvaluationContext context = new DefaultEvaluationContext(identity, session);
|
try {
|
||||||
DecisionResult decisionCollector = new DecisionResult();
|
session.getContext().setRealm(realm);
|
||||||
ResourceServer resourceServer = getRealmManagementResourceServer();
|
Identity identity = root.identity();
|
||||||
Resource roleResource = authz.getStoreFactory().getResourceStore().findByName("Users", resourceServer.getId());
|
EvaluationContext context = new DefaultEvaluationContext(identity, session);
|
||||||
Scope manageScope = getManageScope(resourceServer);
|
DecisionResult decisionCollector = new DecisionResult();
|
||||||
|
ResourceServer resourceServer = getRealmManagementResourceServer();
|
||||||
|
Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, resourceServer.getId());
|
||||||
|
Scope manageScope = getManageScope(resourceServer);
|
||||||
|
|
||||||
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, manageScope);
|
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, manageScope);
|
||||||
PermissionEvaluator from = authz.evaluators().from(permissions, context);
|
PermissionEvaluator from = authz.evaluators().from(permissions, context);
|
||||||
from.evaluate(decisionCollector);
|
from.evaluate(decisionCollector);
|
||||||
if (!decisionCollector.completed()) {
|
if (!decisionCollector.completed()) {
|
||||||
logger.error("Failed to run Users manage check", decisionCollector.getError());
|
logger.error("Failed to run Users manage check", decisionCollector.getError());
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
|
||||||
|
} finally {
|
||||||
|
session.getContext().setRealm(oldRealm);
|
||||||
}
|
}
|
||||||
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResourceServer resourceServer() {
|
||||||
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
return authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Policy managePermission() {
|
||||||
|
ResourceServer server = resourceServer();
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
|
||||||
|
// have to do this because findByName returns a Jpa Entity todo change when fixed
|
||||||
|
return authz.getStoreFactory().getPolicyStore().findById(policy.getId(), server.getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,7 +328,7 @@ public class ClientResource {
|
||||||
|
|
||||||
@Path("roles")
|
@Path("roles")
|
||||||
public RoleContainerResource getRoleContainerResource() {
|
public RoleContainerResource getRoleContainerResource() {
|
||||||
return new RoleContainerResource(uriInfo, realm, auth, client, adminEvent);
|
return new RoleContainerResource(session, uriInfo, realm, auth, client, adminEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
|
import org.keycloak.authorization.admin.permissions.MgmtPermissions;
|
||||||
import org.keycloak.events.admin.OperationType;
|
import org.keycloak.events.admin.OperationType;
|
||||||
import org.keycloak.events.admin.ResourceType;
|
import org.keycloak.events.admin.ResourceType;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
@ -30,6 +31,7 @@ import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
|
import org.keycloak.services.ForbiddenException;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
|
@ -63,6 +65,8 @@ public class ClientRoleMappingsResource {
|
||||||
protected ClientModel client;
|
protected ClientModel client;
|
||||||
protected AdminEventBuilder adminEvent;
|
protected AdminEventBuilder adminEvent;
|
||||||
private UriInfo uriInfo;
|
private UriInfo uriInfo;
|
||||||
|
private RoleMapperResource.ManageResourcePermissionCheck manageResourcePermissionCheck;
|
||||||
|
|
||||||
|
|
||||||
public ClientRoleMappingsResource(UriInfo uriInfo, KeycloakSession session, RealmModel realm, RealmAuth auth, RoleMapperModel user, ClientModel client, AdminEventBuilder adminEvent) {
|
public ClientRoleMappingsResource(UriInfo uriInfo, KeycloakSession session, RealmModel realm, RealmAuth auth, RoleMapperModel user, ClientModel client, AdminEventBuilder adminEvent) {
|
||||||
this.uriInfo = uriInfo;
|
this.uriInfo = uriInfo;
|
||||||
|
@ -74,6 +78,12 @@ public class ClientRoleMappingsResource {
|
||||||
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_ROLE_MAPPING);
|
this.adminEvent = adminEvent.resource(ResourceType.CLIENT_ROLE_MAPPING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setManageCheck(RoleMapperResource.ManageResourcePermissionCheck mapperPermissions) {
|
||||||
|
this.manageResourcePermissionCheck = mapperPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get client-level role mappings for the user, and the app
|
* Get client-level role mappings for the user, and the app
|
||||||
*
|
*
|
||||||
|
@ -157,6 +167,17 @@ public class ClientRoleMappingsResource {
|
||||||
return mappings;
|
return mappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkManagePermission() {
|
||||||
|
if (manageResourcePermissionCheck == null) {
|
||||||
|
auth.requireManage();
|
||||||
|
} else {
|
||||||
|
if (!manageResourcePermissionCheck.canManage()) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add client-level roles to the user role mapping
|
* Add client-level roles to the user role mapping
|
||||||
*
|
*
|
||||||
|
@ -165,7 +186,7 @@ public class ClientRoleMappingsResource {
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void addClientRoleMapping(List<RoleRepresentation> roles) {
|
public void addClientRoleMapping(List<RoleRepresentation> roles) {
|
||||||
auth.requireManage();
|
checkManagePermission();
|
||||||
|
|
||||||
if (user == null || client == null) {
|
if (user == null || client == null) {
|
||||||
throw new NotFoundException("Not found");
|
throw new NotFoundException("Not found");
|
||||||
|
@ -176,21 +197,28 @@ public class ClientRoleMappingsResource {
|
||||||
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
||||||
throw new NotFoundException("Role not found");
|
throw new NotFoundException("Role not found");
|
||||||
}
|
}
|
||||||
|
checkMapRolePermission(roleModel);
|
||||||
user.grantRole(roleModel);
|
user.grantRole(roleModel);
|
||||||
}
|
}
|
||||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
|
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void checkMapRolePermission(RoleModel roleModel) {
|
||||||
* Delete client-level roles from user role mapping
|
if (!new MgmtPermissions(session, realm, auth.getAuth()).roles().canMapRole(roleModel)) {
|
||||||
*
|
throw new ForbiddenException();
|
||||||
* @param roles
|
}
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete client-level roles from user role mapping
|
||||||
|
*
|
||||||
|
* @param roles
|
||||||
|
*/
|
||||||
@DELETE
|
@DELETE
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void deleteClientRoleMapping(List<RoleRepresentation> roles) {
|
public void deleteClientRoleMapping(List<RoleRepresentation> roles) {
|
||||||
auth.requireManage();
|
checkManagePermission();
|
||||||
|
|
||||||
if (user == null || client == null) {
|
if (user == null || client == null) {
|
||||||
throw new NotFoundException("Not found");
|
throw new NotFoundException("Not found");
|
||||||
|
@ -205,6 +233,7 @@ public class ClientRoleMappingsResource {
|
||||||
ClientModel client = (ClientModel) roleModel.getContainer();
|
ClientModel client = (ClientModel) roleModel.getContainer();
|
||||||
if (!client.getId().equals(this.client.getId())) continue;
|
if (!client.getId().equals(this.client.getId())) continue;
|
||||||
}
|
}
|
||||||
|
checkMapRolePermission(roleModel);
|
||||||
user.deleteRoleMapping(roleModel);
|
user.deleteRoleMapping(roleModel);
|
||||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
|
@ -216,6 +245,7 @@ public class ClientRoleMappingsResource {
|
||||||
throw new NotFoundException("Role not found");
|
throw new NotFoundException("Role not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkMapRolePermission(roleModel);
|
||||||
try {
|
try {
|
||||||
user.deleteRoleMapping(roleModel);
|
user.deleteRoleMapping(roleModel);
|
||||||
} catch (ModelException me) {
|
} catch (ModelException me) {
|
||||||
|
|
|
@ -23,6 +23,9 @@ import org.jboss.resteasy.spi.NotFoundException;
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.KeyPairVerifier;
|
import org.keycloak.KeyPairVerifier;
|
||||||
|
import org.keycloak.authorization.admin.permissions.MgmtPermissions;
|
||||||
|
import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions;
|
||||||
|
import org.keycloak.authorization.admin.permissions.UsersPermissions;
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.common.VerificationException;
|
import org.keycloak.common.VerificationException;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
|
@ -44,6 +47,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.LDAPConstants;
|
import org.keycloak.models.LDAPConstants;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.models.cache.CacheRealmProvider;
|
import org.keycloak.models.cache.CacheRealmProvider;
|
||||||
import org.keycloak.models.cache.UserCache;
|
import org.keycloak.models.cache.UserCache;
|
||||||
|
@ -61,6 +65,7 @@ import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
import org.keycloak.representations.idm.EventRepresentation;
|
import org.keycloak.representations.idm.EventRepresentation;
|
||||||
import org.keycloak.representations.idm.GroupRepresentation;
|
import org.keycloak.representations.idm.GroupRepresentation;
|
||||||
|
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||||
import org.keycloak.representations.idm.PartialImportRepresentation;
|
import org.keycloak.representations.idm.PartialImportRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
@ -132,7 +137,6 @@ public class RealmAdminResource {
|
||||||
this.adminEvent = adminEvent.realm(realm).resource(ResourceType.REALM);
|
this.adminEvent = adminEvent.realm(realm).resource(ResourceType.REALM);
|
||||||
|
|
||||||
auth.init(RealmAuth.Resource.REALM);
|
auth.init(RealmAuth.Resource.REALM);
|
||||||
auth.requireAny();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -234,7 +238,7 @@ public class RealmAdminResource {
|
||||||
*/
|
*/
|
||||||
@Path("roles")
|
@Path("roles")
|
||||||
public RoleContainerResource getRoleContainerResource() {
|
public RoleContainerResource getRoleContainerResource() {
|
||||||
return new RoleContainerResource(uriInfo, realm, auth, realm, adminEvent);
|
return new RoleContainerResource(session, uriInfo, realm, auth, realm, adminEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -360,6 +364,51 @@ public class RealmAdminResource {
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NoCache
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Path("users-management-permissions")
|
||||||
|
public ManagementPermissionReference getUserMgmtPermissions() {
|
||||||
|
auth.requireView();
|
||||||
|
|
||||||
|
MgmtPermissions permissions = new MgmtPermissions(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.requireManage();
|
||||||
|
|
||||||
|
MgmtPermissions permissions = new MgmtPermissions(session, realm);
|
||||||
|
permissions.users().setPermissionsEnabled(ref.isEnabled());
|
||||||
|
if (ref.isEnabled()) {
|
||||||
|
return toUsersMgmtRef(permissions);
|
||||||
|
} else {
|
||||||
|
return new ManagementPermissionReference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ManagementPermissionReference toUsersMgmtRef(MgmtPermissions permissions) {
|
||||||
|
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||||
|
ref.setEnabled(true);
|
||||||
|
ref.setResource(permissions.users().resource().getId());
|
||||||
|
Map<String, String> scopes = new HashMap<>();
|
||||||
|
scopes.put(MgmtPermissions.MANAGE_SCOPE, permissions.users().managePermission().getId());
|
||||||
|
ref.setScopePermissions(scopes);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Path("user-storage")
|
@Path("user-storage")
|
||||||
public UserStorageProviderResource userStorage() {
|
public UserStorageProviderResource userStorage() {
|
||||||
UserStorageProviderResource fed = new UserStorageProviderResource(realm, auth, adminEvent);
|
UserStorageProviderResource fed = new UserStorageProviderResource(realm, auth, adminEvent);
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.keycloak.services.resources.admin;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
|
import org.keycloak.authorization.admin.permissions.MgmtPermissions;
|
||||||
|
import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions;
|
||||||
import org.keycloak.events.admin.OperationType;
|
import org.keycloak.events.admin.OperationType;
|
||||||
import org.keycloak.events.admin.ResourceType;
|
import org.keycloak.events.admin.ResourceType;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
@ -26,6 +28,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
@ -39,7 +42,9 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -244,4 +249,63 @@ public class RoleByIdResource extends RoleResource {
|
||||||
deleteComposites(adminEvent, uriInfo, roles, 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) {
|
||||||
|
auth.requireView();
|
||||||
|
|
||||||
|
RoleModel role = getRoleModel(id);
|
||||||
|
|
||||||
|
MgmtPermissions permissions = new MgmtPermissions(session, realm);
|
||||||
|
if (!permissions.roles().isPermissionsEnabled(role)) {
|
||||||
|
return new ManagementPermissionReference();
|
||||||
|
}
|
||||||
|
return toMgmtRef(role, permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManagementPermissionReference toMgmtRef(RoleModel role, MgmtPermissions permissions) {
|
||||||
|
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||||
|
ref.setEnabled(true);
|
||||||
|
ref.setResource(permissions.roles().resource(role).getId());
|
||||||
|
Map<String, String> scopes = new HashMap<>();
|
||||||
|
scopes.put(RoleMgmtPermissions.MAP_ROLE_SCOPE, permissions.roles().mapRolePermission(role).getId());
|
||||||
|
ref.setScopePermissions(scopes);
|
||||||
|
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) {
|
||||||
|
auth.requireManage();
|
||||||
|
|
||||||
|
RoleModel role = getRoleModel(id);
|
||||||
|
|
||||||
|
MgmtPermissions permissions = new MgmtPermissions(session, realm);
|
||||||
|
permissions.roles().setPermissionsEnabled(role, ref.isEnabled());
|
||||||
|
if (ref.isEnabled()) {
|
||||||
|
return toMgmtRef(role, permissions);
|
||||||
|
} else {
|
||||||
|
return new ManagementPermissionReference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,18 @@ package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
|
import org.keycloak.authorization.admin.permissions.MgmtPermissions;
|
||||||
|
import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions;
|
||||||
import org.keycloak.events.admin.OperationType;
|
import org.keycloak.events.admin.OperationType;
|
||||||
import org.keycloak.events.admin.ResourceType;
|
import org.keycloak.events.admin.ResourceType;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleContainerModel;
|
import org.keycloak.models.RoleContainerModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
|
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.services.ErrorResponse;
|
import org.keycloak.services.ErrorResponse;
|
||||||
|
|
||||||
|
@ -44,7 +48,9 @@ import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,14 +64,16 @@ public class RoleContainerResource extends RoleResource {
|
||||||
protected RoleContainerModel roleContainer;
|
protected RoleContainerModel roleContainer;
|
||||||
private AdminEventBuilder adminEvent;
|
private AdminEventBuilder adminEvent;
|
||||||
private UriInfo uriInfo;
|
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, RealmAuth auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent) {
|
||||||
super(realm);
|
super(realm);
|
||||||
this.uriInfo = uriInfo;
|
this.uriInfo = uriInfo;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.roleContainer = roleContainer;
|
this.roleContainer = roleContainer;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent;
|
||||||
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -355,4 +363,67 @@ public class RoleContainerResource extends RoleResource {
|
||||||
deleteComposites(adminEvent, uriInfo, roles, role);
|
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.requireView();
|
||||||
|
|
||||||
|
if (roleContainer == null) {
|
||||||
|
throw new NotFoundException("Could not find client");
|
||||||
|
}
|
||||||
|
|
||||||
|
RoleModel role = roleContainer.getRole(roleName);
|
||||||
|
if (role == null) {
|
||||||
|
throw new NotFoundException("Could not find role");
|
||||||
|
}
|
||||||
|
|
||||||
|
MgmtPermissions permissions = new MgmtPermissions(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.requireManage();
|
||||||
|
|
||||||
|
if (roleContainer == null) {
|
||||||
|
throw new NotFoundException("Could not find client");
|
||||||
|
}
|
||||||
|
|
||||||
|
RoleModel role = roleContainer.getRole(roleName);
|
||||||
|
if (role == null) {
|
||||||
|
throw new NotFoundException("Could not find role");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ref.isEnabled()) {
|
||||||
|
MgmtPermissions permissions = new MgmtPermissions(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.logging.Logger;
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
|
import org.keycloak.authorization.admin.permissions.MgmtPermissions;
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.events.admin.OperationType;
|
import org.keycloak.events.admin.OperationType;
|
||||||
import org.keycloak.events.admin.ResourceType;
|
import org.keycloak.events.admin.ResourceType;
|
||||||
|
@ -33,6 +34,7 @@ import org.keycloak.representations.idm.ClientMappingsRepresentation;
|
||||||
import org.keycloak.representations.idm.MappingsRepresentation;
|
import org.keycloak.representations.idm.MappingsRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
|
import org.keycloak.services.ForbiddenException;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
@ -64,6 +66,17 @@ import java.util.Set;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class RoleMapperResource {
|
public class RoleMapperResource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RoleMapperResource is reused bewteen GroupResource and UserResource to manage role mappings.
|
||||||
|
* We don't know what type of resource we're managing here (user or group), so we don't know how to query the policy engine to determine
|
||||||
|
* if an action is allowed.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ManageResourcePermissionCheck {
|
||||||
|
boolean canManage();
|
||||||
|
}
|
||||||
|
|
||||||
protected static final Logger logger = Logger.getLogger(RoleMapperResource.class);
|
protected static final Logger logger = Logger.getLogger(RoleMapperResource.class);
|
||||||
|
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
|
@ -74,6 +87,8 @@ public class RoleMapperResource {
|
||||||
|
|
||||||
private AdminEventBuilder adminEvent;
|
private AdminEventBuilder adminEvent;
|
||||||
|
|
||||||
|
private ManageResourcePermissionCheck manageResourcePermissionCheck;
|
||||||
|
|
||||||
@Context
|
@Context
|
||||||
protected ClientConnection clientConnection;
|
protected ClientConnection clientConnection;
|
||||||
|
|
||||||
|
@ -94,6 +109,9 @@ public class RoleMapperResource {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setManageCheck(ManageResourcePermissionCheck mapperPermissions) {
|
||||||
|
this.manageResourcePermissionCheck = mapperPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get role mappings
|
* Get role mappings
|
||||||
|
@ -224,7 +242,7 @@ public class RoleMapperResource {
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void addRealmRoleMappings(List<RoleRepresentation> roles) {
|
public void addRealmRoleMappings(List<RoleRepresentation> roles) {
|
||||||
auth.requireManage();
|
checkManagePermission();
|
||||||
|
|
||||||
if (roleMapper == null) {
|
if (roleMapper == null) {
|
||||||
throw new NotFoundException("User not found");
|
throw new NotFoundException("User not found");
|
||||||
|
@ -237,12 +255,23 @@ public class RoleMapperResource {
|
||||||
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
||||||
throw new NotFoundException("Role not found");
|
throw new NotFoundException("Role not found");
|
||||||
}
|
}
|
||||||
|
checkMapRolePermission(roleModel);
|
||||||
roleMapper.grantRole(roleModel);
|
roleMapper.grantRole(roleModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
|
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkManagePermission() {
|
||||||
|
if (manageResourcePermissionCheck == null) {
|
||||||
|
auth.requireManage();
|
||||||
|
} else {
|
||||||
|
if (!manageResourcePermissionCheck.canManage()) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete realm-level role mappings
|
* Delete realm-level role mappings
|
||||||
*
|
*
|
||||||
|
@ -252,7 +281,7 @@ public class RoleMapperResource {
|
||||||
@DELETE
|
@DELETE
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void deleteRealmRoleMappings(List<RoleRepresentation> roles) {
|
public void deleteRealmRoleMappings(List<RoleRepresentation> roles) {
|
||||||
auth.requireManage();
|
checkManagePermission();
|
||||||
|
|
||||||
if (roleMapper == null) {
|
if (roleMapper == null) {
|
||||||
throw new NotFoundException("User not found");
|
throw new NotFoundException("User not found");
|
||||||
|
@ -264,6 +293,7 @@ public class RoleMapperResource {
|
||||||
roles = new LinkedList<>();
|
roles = new LinkedList<>();
|
||||||
|
|
||||||
for (RoleModel roleModel : roleModels) {
|
for (RoleModel roleModel : roleModels) {
|
||||||
|
checkMapRolePermission(roleModel);
|
||||||
roleMapper.deleteRoleMapping(roleModel);
|
roleMapper.deleteRoleMapping(roleModel);
|
||||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
|
@ -274,7 +304,7 @@ public class RoleMapperResource {
|
||||||
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
|
||||||
throw new NotFoundException("Role not found");
|
throw new NotFoundException("Role not found");
|
||||||
}
|
}
|
||||||
|
checkMapRolePermission(roleModel);
|
||||||
try {
|
try {
|
||||||
roleMapper.deleteRoleMapping(roleModel);
|
roleMapper.deleteRoleMapping(roleModel);
|
||||||
} catch (ModelException me) {
|
} catch (ModelException me) {
|
||||||
|
@ -290,10 +320,20 @@ public class RoleMapperResource {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkMapRolePermission(RoleModel roleModel) {
|
||||||
|
if (!new MgmtPermissions(session, realm, auth.getAuth()).roles().canMapRole(roleModel)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Path("clients/{client}")
|
@Path("clients/{client}")
|
||||||
public ClientRoleMappingsResource getUserClientRoleMappingsResource(@PathParam("client") String client) {
|
public ClientRoleMappingsResource getUserClientRoleMappingsResource(@PathParam("client") String client) {
|
||||||
ClientModel clientModel = realm.getClientById(client);
|
ClientModel clientModel = realm.getClientById(client);
|
||||||
return new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper, clientModel, adminEvent);
|
ClientRoleMappingsResource resource = new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper, clientModel, adminEvent);
|
||||||
|
resource.setManageCheck(() -> {
|
||||||
|
return new MgmtPermissions(session, realm, auth.getAuth()).users().canManage();
|
||||||
|
});
|
||||||
|
return resource;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.jboss.resteasy.spi.BadRequestException;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
import org.keycloak.authentication.RequiredActionProvider;
|
import org.keycloak.authentication.RequiredActionProvider;
|
||||||
|
import org.keycloak.authorization.admin.permissions.MgmtPermissions;
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.common.Profile;
|
import org.keycloak.common.Profile;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
|
@ -48,9 +49,7 @@ import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserLoginFailureModel;
|
import org.keycloak.models.UserLoginFailureModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.models.credential.PasswordUserCredentialModel;
|
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
import org.keycloak.models.utils.RepresentationToModel;
|
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.protocol.oidc.utils.RedirectUtils;
|
import org.keycloak.protocol.oidc.utils.RedirectUtils;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
@ -723,6 +722,9 @@ public class UsersResource {
|
||||||
UserModel user = session.users().getUserById(id, realm);
|
UserModel user = session.users().getUserById(id, realm);
|
||||||
|
|
||||||
RoleMapperResource resource = new RoleMapperResource(realm, auth, user, adminEvent);
|
RoleMapperResource resource = new RoleMapperResource(realm, auth, user, adminEvent);
|
||||||
|
resource.setManageCheck(() -> {
|
||||||
|
return new MgmtPermissions(session, realm, auth.getAuth()).users().canManage();
|
||||||
|
});
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||||
return resource;
|
return resource;
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,15 @@ import static org.keycloak.testsuite.util.IOUtil.PROJECT_BUILD_DIRECTORY;
|
||||||
public class AdminClientUtil {
|
public class AdminClientUtil {
|
||||||
|
|
||||||
public static Keycloak createAdminClient(boolean ignoreUnknownProperties) throws Exception {
|
public static Keycloak createAdminClient(boolean ignoreUnknownProperties) throws Exception {
|
||||||
|
String realmName = MASTER;
|
||||||
|
String username = ADMIN;
|
||||||
|
String password = ADMIN;
|
||||||
|
String clientId = Constants.ADMIN_CLI_CLIENT_ID;
|
||||||
|
String clientSecret = null;
|
||||||
|
return createAdminClient(ignoreUnknownProperties, realmName, username, password, clientId, clientSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String realmName, String username, String password, String clientId, String clientSecret) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {
|
||||||
SSLContext ssl = null;
|
SSLContext ssl = null;
|
||||||
if ("true".equals(System.getProperty("auth.server.ssl.required"))) {
|
if ("true".equals(System.getProperty("auth.server.ssl.required"))) {
|
||||||
File trustore = new File(PROJECT_BUILD_DIRECTORY, "dependency/keystore/keycloak.truststore");
|
File trustore = new File(PROJECT_BUILD_DIRECTORY, "dependency/keystore/keycloak.truststore");
|
||||||
|
@ -62,7 +71,7 @@ public class AdminClientUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
|
return Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/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 {
|
public static Keycloak createAdminClient() throws Exception {
|
||||||
|
|
|
@ -1,260 +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.AuthorizationProviderFactory;
|
|
||||||
import org.keycloak.authorization.Decision;
|
|
||||||
import org.keycloak.authorization.common.DefaultEvaluationContext;
|
|
||||||
import org.keycloak.authorization.common.UserModelIdentity;
|
|
||||||
import org.keycloak.authorization.model.Policy;
|
|
||||||
import org.keycloak.authorization.model.Resource;
|
|
||||||
import org.keycloak.authorization.model.ResourceServer;
|
|
||||||
import org.keycloak.authorization.model.Scope;
|
|
||||||
import org.keycloak.authorization.permission.ResourcePermission;
|
|
||||||
import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
|
|
||||||
import org.keycloak.authorization.policy.evaluation.DecisionResult;
|
|
||||||
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
|
||||||
import org.keycloak.authorization.util.Permissions;
|
|
||||||
import org.keycloak.models.AdminRoles;
|
|
||||||
import org.keycloak.models.ClientModel;
|
|
||||||
import org.keycloak.models.Constants;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.RoleModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.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.LinkedList;
|
|
||||||
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(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
|
||||||
|
|
||||||
AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
|
|
||||||
AuthorizationProvider authz = factory.create(session, realm);
|
|
||||||
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);
|
|
||||||
addEmptyScopePermission(authz, resourceServer, "empty. " + name, resource, mapRoleScope);
|
|
||||||
|
|
||||||
}
|
|
||||||
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 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
session.getContext().setRealm(realm);
|
|
||||||
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());
|
|
||||||
Scope mapRoleScope = authz.getStoreFactory().getScopeStore().findByName("map-role", resourceServer.getId());
|
|
||||||
|
|
||||||
UserModelIdentity identity = new UserModelIdentity(realm, admin);
|
|
||||||
EvaluationContext context = new DefaultEvaluationContext(identity, session);
|
|
||||||
DecisionResult decisionCollector = new DecisionResult();
|
|
||||||
|
|
||||||
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
|
|
||||||
PermissionEvaluator from = authz.evaluators().from(permissions, context);
|
|
||||||
from.evaluate(decisionCollector);
|
|
||||||
if (!decisionCollector.completed()) {
|
|
||||||
decisionCollector.getError().printStackTrace();
|
|
||||||
}
|
|
||||||
Assert.assertTrue(decisionCollector.completed());
|
|
||||||
Assert.assertEquals(decisionCollector.getResults().get(0).getEffect(), Decision.Effect.PERMIT);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEvaluation2() throws Exception {
|
|
||||||
testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
|
|
||||||
testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
|
|
||||||
testingClient.server().run(FineGrainAdminLocalTest::evaluateAdminHasManageRealmPermissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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,336 @@
|
||||||
|
/*
|
||||||
|
* 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.admin.client.resource.RealmResource;
|
||||||
|
import org.keycloak.authorization.admin.permissions.MgmtPermissions;
|
||||||
|
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.DecisionEffect;
|
||||||
|
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||||
|
import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
|
||||||
|
import org.keycloak.representations.idm.authorization.PolicyEvaluationResponse;
|
||||||
|
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||||
|
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
|
||||||
|
import org.keycloak.testsuite.util.AdminClientUtil;
|
||||||
|
|
||||||
|
import javax.ws.rs.ClientErrorException;
|
||||||
|
import javax.ws.rs.ForbiddenException;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
|
||||||
|
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
|
||||||
|
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
//@Ignore
|
||||||
|
public class FineGrainAdminUnitTest 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 setupPolices(KeycloakSession session) {
|
||||||
|
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||||
|
MgmtPermissions permissions = new MgmtPermissions(session, realm);
|
||||||
|
RoleModel realmRole = realm.addRole("realm-role");
|
||||||
|
RoleModel realmRole2 = realm.addRole("realm-role2");
|
||||||
|
ClientModel client1 = realm.addClient("role-namespace");
|
||||||
|
RoleModel client1Role = client1.addRole("client-role");
|
||||||
|
|
||||||
|
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 role-namespace.client-role will have a role policy associated with their map-role permission
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// realmRole2 will have an empty map-role policy
|
||||||
|
{
|
||||||
|
permissions.roles().setPermissionsEnabled(realmRole2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup Users manage policies
|
||||||
|
{
|
||||||
|
permissions.users().setPermissionsEnabled(true);
|
||||||
|
ResourceServer server = permissions.users().resourceServer();
|
||||||
|
Policy managerPolicy = permissions.roles().rolePolicy(server, managerRole);
|
||||||
|
Policy permission = permissions.users().managePermission();
|
||||||
|
permission.addAssociatedPolicy(managerPolicy);
|
||||||
|
permission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setupUsers(KeycloakSession session) {
|
||||||
|
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||||
|
ClientModel client = realm.getClientByClientId("role-namespace");
|
||||||
|
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");
|
||||||
|
|
||||||
|
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);
|
||||||
|
UserModel user2 = session.users().addUser(realm, "user2");
|
||||||
|
user2.setEnabled(true);
|
||||||
|
UserModel user3 = session.users().addUser(realm, "user3");
|
||||||
|
user3.setEnabled(true);
|
||||||
|
UserModel user4 = session.users().addUser(realm, "user4");
|
||||||
|
user4.setEnabled(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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("role-namespace");
|
||||||
|
RoleModel clientRole = client.getRole("client-role");
|
||||||
|
|
||||||
|
// test authorized
|
||||||
|
{
|
||||||
|
UserModel user = session.users().getUserByUsername("authorized", realm);
|
||||||
|
MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm);
|
||||||
|
permissionsForAdmin.setIdentity(user);
|
||||||
|
Assert.assertTrue(permissionsForAdmin.users().canManage(user));
|
||||||
|
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
|
||||||
|
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||||
|
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
|
||||||
|
}
|
||||||
|
// test composite role
|
||||||
|
{
|
||||||
|
UserModel user = session.users().getUserByUsername("authorizedComposite", realm);
|
||||||
|
MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm);
|
||||||
|
permissionsForAdmin.setIdentity(user);
|
||||||
|
Assert.assertTrue(permissionsForAdmin.users().canManage(user));
|
||||||
|
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
|
||||||
|
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||||
|
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
// test unauthorized
|
||||||
|
{
|
||||||
|
UserModel user = session.users().getUserByUsername("unauthorized", realm);
|
||||||
|
MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm);
|
||||||
|
permissionsForAdmin.setIdentity(user);
|
||||||
|
Assert.assertFalse(permissionsForAdmin.users().canManage(user));
|
||||||
|
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.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||||
|
}
|
||||||
|
// test unauthorized mapper
|
||||||
|
{
|
||||||
|
UserModel user = session.users().getUserByUsername("unauthorizedMapper", realm);
|
||||||
|
MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm);
|
||||||
|
permissionsForAdmin.setIdentity(user);
|
||||||
|
Assert.assertTrue(permissionsForAdmin.users().canManage(user));
|
||||||
|
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.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected boolean isImportAfterEachMethod() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUI() throws Exception {
|
||||||
|
testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
|
||||||
|
testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
|
||||||
|
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 user2 = adminClient.realm(TEST).users().search("user2").get(0);
|
||||||
|
UserRepresentation user3 = adminClient.realm(TEST).users().search("user3").get(0);
|
||||||
|
UserRepresentation user4 = adminClient.realm(TEST).users().search("user4").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("role-namespace").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(),
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1290,8 +1290,13 @@ disable-credentials=Disable Credentials
|
||||||
credential-reset-actions=Credential Reset
|
credential-reset-actions=Credential Reset
|
||||||
ldap-mappers=LDAP Mappers
|
ldap-mappers=LDAP Mappers
|
||||||
create-ldap-mapper=Create LDAP mapper
|
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-mgmt-scope-description=Policies that decide if an admin can manage this resource or resources
|
||||||
|
permissions-enabled-role=Permissions Enabled
|
||||||
|
permissions-enabled-role.tooltip=Whether or not to enable fine grain permissions for 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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2345,6 +2345,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 () {
|
module.directive('kcTabsUser', function () {
|
||||||
return {
|
return {
|
||||||
scope: true,
|
scope: true,
|
||||||
|
|
|
@ -373,7 +373,41 @@ module.config(['$routeProvider', function ($routeProvider) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
controller: 'ResourceServerPolicyAggregateDetailCtrl'
|
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'
|
||||||
|
})
|
||||||
|
;
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
module.directive('kcTabsResourceServer', function () {
|
module.directive('kcTabsResourceServer', function () {
|
||||||
|
|
|
@ -2354,3 +2354,60 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio
|
||||||
$scope.authzRequest.userId = user.id;
|
$scope.authzRequest.userId = user.id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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: 'realm-management'}, function(data) {
|
||||||
|
$scope.realmManagementClientId = data[0].id;
|
||||||
|
});
|
||||||
|
$scope.setEnabled = function() {
|
||||||
|
var param = { enabled: $scope.permissions.enabled};
|
||||||
|
RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param, function(data) {
|
||||||
|
$scope.permissions = data;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
module.controller('ClientRolePermissionsCtrl', function($scope, $http, $route, $location, realm, client, role, 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;
|
||||||
|
});
|
||||||
|
$scope.setEnabled = function() {
|
||||||
|
var param = { enabled: $scope.permissions.enabled};
|
||||||
|
RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param, function(data) {
|
||||||
|
$scope.permissions = data;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
module.controller('UsersPermissionsCtrl', function($scope, $http, $route, $location, realm, UsersManagementPermissions, Client, Notifications) {
|
||||||
|
console.log('UsersPermissionsCtrl');
|
||||||
|
$scope.realm = realm;
|
||||||
|
UsersManagementPermissions.get({realm: realm.realm, role: role.id}, function(data) {
|
||||||
|
$scope.permissions = data;
|
||||||
|
});
|
||||||
|
Client.query({realm: realm.realm, clientId: 'realm-management'}, function(data) {
|
||||||
|
$scope.realmManagementClientId = data[0].id;
|
||||||
|
});
|
||||||
|
$scope.setEnabled = function() {
|
||||||
|
var param = { enabled: $scope.permissions.enabled};
|
||||||
|
UsersManagementPermissions.update({realm: realm.realm, role:role.id}, param, function(data) {
|
||||||
|
$scope.permissions = data;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -1326,6 +1326,21 @@ module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevoca
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
module.controller('RoleTabCtrl', function(Dialog, $scope, Current, Notifications, $location) {
|
||||||
|
$scope.removeRole = function() {
|
||||||
|
Dialog.confirmDelete($scope.role.name, 'role', function() {
|
||||||
|
RoleById.remove({
|
||||||
|
realm: realm.realm,
|
||||||
|
role: $scope.role.id
|
||||||
|
}, function () {
|
||||||
|
$route.reload();
|
||||||
|
Notifications.success("The role has been deleted.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.controller('RoleListCtrl', function($scope, $route, Dialog, Notifications, realm, roles, RoleById, filterFilter) {
|
module.controller('RoleListCtrl', function($scope, $route, Dialog, Notifications, realm, roles, RoleById, filterFilter) {
|
||||||
$scope.realm = realm;
|
$scope.realm = realm;
|
||||||
$scope.roles = roles;
|
$scope.roles = roles;
|
||||||
|
|
|
@ -841,6 +841,28 @@ module.factory('Role', function($resource) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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('RoleById', function($resource) {
|
module.factory('RoleById', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role', {
|
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role', {
|
||||||
realm : '@realm',
|
realm : '@realm',
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles">{{:: 'roles' | translate}}</a></li>
|
||||||
|
<li>{{role.name}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<kc-tabs-client-role></kc-tabs-client-role>
|
||||||
|
|
||||||
|
<form class=form-horizontal" name="enableForm" novalidate kc-read-only="!access.manageAuthorization">
|
||||||
|
<fieldset class="border-top">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="permissionsEnabled">{{:: 'permissions-enabled-role' | translate}}</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input ng-model="permissions.enabled" ng-click="setEnabled()" name="permissionsEnabled" id="permissionsEnabled" ng-disabled="!access.manageAuthorization" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'permissions-enabled-role.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
<table class="datatable table table-striped table-bordered dataTable no-footer" data-ng-show="permissions.enabled">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{:: 'scope-name' | translate}}</th>
|
||||||
|
<th>{{:: 'description' | translate}}</th>
|
||||||
|
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="(scopeName, scopeId) in permissions.scopePermissions">
|
||||||
|
<td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
|
||||||
|
<td translate="{{scopeName}}-mgmt-scope-description"></td>
|
||||||
|
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/scope/{{scopeId}}">{{:: 'edit' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/roles">{{:: 'roles' | translate}}</a></li>
|
||||||
|
<li>{{role.name}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<kc-tabs-role></kc-tabs-role>
|
||||||
|
|
||||||
|
<form class=form-horizontal" name="enableForm" novalidate kc-read-only="!access.manageAuthorization">
|
||||||
|
<fieldset class="border-top">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="permissionsEnabled">{{:: 'permissions-enabled' | translate}}</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input ng-model="permissions.enabled" ng-click="setEnabled()" name="permissionsEnabled" id="permissionsEnabled" ng-disabled="!access.manageAuthorization" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'permissions-enabled.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
<table class="datatable table table-striped table-bordered dataTable no-footer" data-ng-show="permissions.enabled">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{:: 'scope-name' | translate}}</th>
|
||||||
|
<th>{{:: 'description' | translate}}</th>
|
||||||
|
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="(scopeName, scopeId) in permissions.scopePermissions">
|
||||||
|
<td><a href="#/realms/{{realm.realm}}/clients/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
|
||||||
|
<td translate="{{scopeName}}-mgmt-scope-description"></td>
|
||||||
|
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{:: 'edit' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -0,0 +1,35 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
|
||||||
|
<kc-tabs-users></kc-tabs-users>
|
||||||
|
|
||||||
|
<form class=form-horizontal" name="enableForm" novalidate kc-read-only="!access.manageAuthorization">
|
||||||
|
<fieldset class="border-top">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="permissionsEnabled">{{:: 'permissions-enabled' | translate}}</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input ng-model="permissions.enabled" ng-click="setEnabled()" name="permissionsEnabled" id="permissionsEnabled" ng-disabled="!access.manageAuthorization" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'permissions-enabled.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
<table class="datatable table table-striped table-bordered dataTable no-footer" data-ng-show="permissions.enabled">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{:: 'scope-name' | translate}}</th>
|
||||||
|
<th>{{:: 'description' | translate}}</th>
|
||||||
|
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="(scopeName, scopeId) in permissions.scopePermissions">
|
||||||
|
<td><a href="#/realms/{{realm.realm}}/clients/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
|
||||||
|
<td translate="{{scopeName}}-mgmt-scope-description"></td>
|
||||||
|
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{:: 'edit' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -8,9 +8,7 @@
|
||||||
<li data-ng-hide="create">{{role.name}}</li>
|
<li data-ng-hide="create">{{role.name}}</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<h1 data-ng-show="create">{{:: 'add-role' | translate}}</h1>
|
<kc-tabs-client-role></kc-tabs-client-role>
|
||||||
<h1 data-ng-hide="create">{{role.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create && access.manageClients"
|
|
||||||
data-ng-hide="changed" data-ng-click="remove()"></i></h1>
|
|
||||||
|
|
||||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients">
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients">
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
<li data-ng-show="create">{{:: 'add-role' | translate}}</li>
|
<li data-ng-show="create">{{:: 'add-role' | translate}}</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<h1 data-ng-hide="create">{{role.name|capitalize}} <i id="removeRole" class="pficon pficon-delete clickable" data-ng-show="!create && access.manageRealm"
|
<kc-tabs-role></kc-tabs-role>
|
||||||
data-ng-hide="changed" data-ng-click="remove()"></i></h1>
|
|
||||||
<h1 data-ng-show="create">{{:: 'add-role' | translate}}</h1>
|
|
||||||
|
|
||||||
<form class="form-horizontal clearfix" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
<form class="form-horizontal clearfix" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2" ng-init="init()">
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2" ng-init="init()">
|
||||||
<h1>{{:: 'users' | translate}}</h1>
|
|
||||||
|
<kc-tabs-users></kc-tabs-users>
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<caption data-ng-show="users" class="hidden">{{:: 'table-of-realm-users' | translate}}</caption>
|
<caption data-ng-show="users" class="hidden">{{:: 'table-of-realm-users' | translate}}</caption>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div data-ng-controller="RoleTabCtrl">
|
||||||
|
<h1 data-ng-show="create">{{:: 'add-role' | translate}}</h1>
|
||||||
|
<h1 data-ng-hide="create">{{role.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create && access.manageClients"
|
||||||
|
data-ng-hide="changed" data-ng-click="remove()"></i></h1>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" data-ng-show="!create">
|
||||||
|
<li ng-class="{active: !path[6]}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}">{{:: 'details' | translate}}</a></li>
|
||||||
|
<li ng-class="{active: path[6] && path[6] == 'permissions'}">
|
||||||
|
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
|
||||||
|
<kc-tooltip>{{:: 'manage-permissions-role.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div data-ng-controller="RoleTabCtrl">
|
||||||
|
<h1 data-ng-hide="create">{{role.name|capitalize}} <i id="removeRole" class="pficon pficon-delete clickable" data-ng-show="!create && access.manageRealm"
|
||||||
|
data-ng-hide="changed" data-ng-click="remove()"></i></h1>
|
||||||
|
<h1 data-ng-show="create">{{:: 'add-role' | translate}}</h1>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" data-ng-show="!create">
|
||||||
|
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/roles/{{role.id}}">{{:: 'details' | translate}}</a></li>
|
||||||
|
<li ng-class="{active: path[4] == 'permissions'}">
|
||||||
|
<a href="#/realms/{{realm.realm}}/roles/{{role.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
|
||||||
|
<kc-tooltip>{{:: 'manage-permissions-role.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<div >
|
||||||
|
<h1>{{:: 'users' | translate}}</h1>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li ng-class="{active: path[2] == 'users'}"><a href="#/realms/{{realm.realm}}/users">{{:: 'lookup' | translate}}</a></li>
|
||||||
|
<li ng-class="{active: path[2] == 'users-permissions'}">
|
||||||
|
<a href="#/realms/{{realm.realm}}/users-permissions">{{:: 'authz-permissions' | translate}}</a>
|
||||||
|
<kc-tooltip>{{:: 'manage-permissions-users.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
Loading…
Reference in a new issue