remove scope

This commit is contained in:
Bill Burke 2017-06-16 11:26:43 -04:00
parent 94528976d4
commit a994af9010
33 changed files with 612 additions and 188 deletions

View file

@ -31,12 +31,15 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyException;
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.util.TokenUtil;
import javax.ws.rs.core.HttpHeaders;
@ -231,44 +234,72 @@ public class ClientRegistrationAuth {
return initialAccessModel;
}
private boolean hasRole(String... role) {
private boolean hasRole(String... roles) {
try {
Map<String, Object> otherClaims = jwt.getOtherClaims();
if (otherClaims != null) {
Map<String, Map<String, List<String>>> resourceAccess = (Map<String, Map<String, List<String>>>) jwt.getOtherClaims().get("resource_access");
if (resourceAccess == null) {
return false;
}
if (jwt.getIssuedFor().equals(Constants.ADMIN_CLI_CLIENT_ID)
|| jwt.getIssuedFor().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
return hasRoleInModel(roles);
List<String> roles = null;
Map<String, List<String>> map;
if (realm.getName().equals(Config.getAdminRealm())) {
map = resourceAccess.get(realm.getMasterAdminClient().getClientId());
} else {
map = resourceAccess.get(Constants.REALM_MANAGEMENT_CLIENT_ID);
}
if (map != null) {
roles = map.get("roles");
}
if (roles == null) {
return false;
}
for (String r : role) {
if (roles.contains(r)) {
return true;
}
}
} else {
return hasRoleInToken(roles);
}
return false;
} catch (Throwable t) {
return false;
}
}
private boolean hasRoleInModel(String[] roles) {
ClientModel roleNamespace;
UserModel user = session.users().getUserById(jwt.getSubject(), realm);
if (user == null) {
return false;
}
if (realm.getName().equals(Config.getAdminRealm())) {
roleNamespace = realm.getMasterAdminClient();
} else {
roleNamespace = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
}
for (String role : roles) {
RoleModel roleModel = roleNamespace.getRole(role);
if (user.hasRole(roleModel)) return true;
}
return false;
}
private boolean hasRoleInToken(String[] role) {
Map<String, Object> otherClaims = jwt.getOtherClaims();
if (otherClaims != null) {
Map<String, Map<String, List<String>>> resourceAccess = (Map<String, Map<String, List<String>>>) jwt.getOtherClaims().get("resource_access");
if (resourceAccess == null) {
return false;
}
List<String> roles = null;
Map<String, List<String>> map;
if (realm.getName().equals(Config.getAdminRealm())) {
map = resourceAccess.get(realm.getMasterAdminClient().getClientId());
} else {
map = resourceAccess.get(Constants.REALM_MANAGEMENT_CLIENT_ID);
}
if (map != null) {
roles = map.get("roles");
}
if (roles == null) {
return false;
}
for (String r : role) {
if (roles.contains(r)) {
return true;
}
}
}
return false;
}
private boolean authenticateClient(ClientModel client) {
if (client == null) {
return false;

View file

@ -159,7 +159,6 @@ public class RealmManager {
ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
}
adminConsole.addScopeMapping(adminRole);
}
protected void setupAdminConsoleLocaleMapper(RealmModel realm) {
@ -194,7 +193,6 @@ public class RealmManager {
ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
}
adminCli.addScopeMapping(adminRole);
}
}

View file

@ -834,7 +834,7 @@ public class AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public List<RequiredActionProviderRepresentation> getRequiredActions() {
auth.realm().requireViewRealm();
auth.requireAnyAdminRole();
List<RequiredActionProviderRepresentation> list = new LinkedList<>();
for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) {

View file

@ -140,7 +140,7 @@ public class ClientRoleMappingsResource {
Set<RoleModel> available = client.getRoles();
available = available.stream().filter(r ->
canMapRole(r)
auth.roles().canMapRole(r)
).collect(Collectors.toSet());
return getAvailableRoles(user, available);
}
@ -174,23 +174,13 @@ public class ClientRoleMappingsResource {
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
throw new NotFoundException("Role not found");
}
checkMapRolePermission(roleModel);
auth.roles().requireMapRole(roleModel);
user.grantRole(roleModel);
}
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
}
private void checkMapRolePermission(RoleModel roleModel) {
if (!canMapRole(roleModel)) {
throw new ForbiddenException();
}
}
private boolean canMapRole(RoleModel roleModel) {
return auth.roles().canMapRole(roleModel);
}
/**
* Delete client-level roles from user role mapping
*
@ -210,7 +200,7 @@ public class ClientRoleMappingsResource {
ClientModel client = (ClientModel) roleModel.getContainer();
if (!client.getId().equals(this.client.getId())) continue;
}
checkMapRolePermission(roleModel);
auth.roles().requireMapRole(roleModel);
user.deleteRoleMapping(roleModel);
roles.add(ModelToRepresentation.toRepresentation(roleModel));
}
@ -222,7 +212,7 @@ public class ClientRoleMappingsResource {
throw new NotFoundException("Role not found");
}
checkMapRolePermission(roleModel);
auth.roles().requireMapRole(roleModel);
try {
user.deleteRoleMapping(roleModel);
} catch (ModelException me) {

View file

@ -76,13 +76,20 @@ public class ClientTemplatesResource {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public List<ClientTemplateRepresentation> getClientTemplates() {
auth.clients().requireView();
auth.clients().requireListTemplates();
List<ClientTemplateRepresentation> rep = new ArrayList<>();
List<ClientTemplateModel> clientModels = realm.getClientTemplates();
boolean viewable = auth.clients().canViewTemplates();
for (ClientTemplateModel clientModel : clientModels) {
rep.add(ModelToRepresentation.toRepresentation(clientModel));
if (viewable) rep.add(ModelToRepresentation.toRepresentation(clientModel));
else {
ClientTemplateRepresentation tempRep = new ClientTemplateRepresentation();
tempRep.setName(clientModel.getName());
tempRep.setId(clientModel.getId());
tempRep.setProtocol(clientModel.getProtocol());
}
}
return rep;
}

View file

@ -96,18 +96,11 @@ public class RealmsAdminResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public List<RealmRepresentation> getRealms() {
RealmManager realmManager = new RealmManager(session);
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
List<RealmModel> realms = session.realms().getRealms();
for (RealmModel realm : realms) {
addRealmRep(reps, realm, realm.getMasterAdminClient());
}
} else {
ClientModel adminApp = auth.getRealm().getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm()));
addRealmRep(reps, auth.getRealm(), adminApp);
List<RealmModel> realms = session.realms().getRealms();
for (RealmModel realm : realms) {
addRealmRep(reps, realm);
}
if (reps.isEmpty()) {
throw new ForbiddenException();
}
@ -116,10 +109,10 @@ public class RealmsAdminResource {
return reps;
}
protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm, ClientModel realmManagementClient) {
if (auth.hasAppRole(realmManagementClient, AdminRoles.VIEW_REALM)) {
protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm) {
if (AdminPermissions.realms(session, auth).canView(realm)) {
reps.add(ModelToRepresentation.toRepresentation(realm, false));
} else if (auth.hasOneOfAppRole(realmManagementClient, AdminRoles.ALL_REALM_ROLES)) {
} else if (AdminPermissions.realms(session, auth).isAdmin(realm)) {
RealmRepresentation rep = new RealmRepresentation();
rep.setRealm(realm.getName());
reps.add(rep);
@ -140,12 +133,7 @@ public class RealmsAdminResource {
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
RealmManager realmManager = new RealmManager(session);
realmManager.setContextPath(keycloak.getContextPath());
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
throw new ForbiddenException();
}
if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
throw new ForbiddenException();
}
AdminPermissions.realms(session, auth).requireCreateRealm();
logger.debugv("importRealm: {0}", rep.getRealm());

View file

@ -232,7 +232,7 @@ public class RoleMapperResource {
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
throw new NotFoundException("Role not found");
}
checkMapRolePermission(roleModel);
auth.roles().requireMapRole(roleModel);
roleMapper.grantRole(roleModel);
}
@ -256,7 +256,7 @@ public class RoleMapperResource {
roles = new LinkedList<>();
for (RoleModel roleModel : roleModels) {
checkMapRolePermission(roleModel);
auth.roles().requireMapRole(roleModel);
roleMapper.deleteRoleMapping(roleModel);
roles.add(ModelToRepresentation.toRepresentation(roleModel));
}
@ -267,7 +267,7 @@ public class RoleMapperResource {
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
throw new NotFoundException("Role not found");
}
checkMapRolePermission(roleModel);
auth.roles().requireMapRole(roleModel);
try {
roleMapper.deleteRoleMapping(roleModel);
} catch (ModelException me) {
@ -283,12 +283,6 @@ public class RoleMapperResource {
}
private void checkMapRolePermission(RoleModel roleModel) {
if (!canMapRole(roleModel)) {
throw new ForbiddenException();
}
}
private boolean canMapRole(RoleModel roleModel) {
return auth.roles().canMapRole(roleModel);
}

View file

@ -67,7 +67,7 @@ public abstract class RoleResource {
if (composite == null) {
throw new NotFoundException("Could not find composite role");
}
auth.roles().requireManage(composite);
auth.roles().requireMapComposite(composite);
role.addCompositeRole(composite);
}

View file

@ -534,7 +534,7 @@ public class UserResource {
@Path("role-mappings")
public RoleMapperResource getRoleMappings() {
AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.users().requireManage(user);
AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.users().requireMapRoles(user);
AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.users().requireView(user);
RoleMapperResource resource = new RoleMapperResource(realm, auth, user, adminEvent, manageCheck, viewCheck);
ResteasyProviderFactory.getInstance().injectProperties(resource);
@ -756,13 +756,13 @@ public class UserResource {
@Path("groups/{groupId}")
@NoCache
public void removeMembership(@PathParam("groupId") String groupId) {
auth.users().requireManage(user);
auth.users().requireManageGroupMembership(user);
GroupModel group = session.realms().getGroupById(groupId, realm);
if (group == null) {
throw new NotFoundException("Group not found");
}
auth.groups().requireManageMembers(group);
auth.groups().requireManageMembership(group);
try {
if (user.isMemberOf(group)){
@ -780,12 +780,12 @@ public class UserResource {
@Path("groups/{groupId}")
@NoCache
public void joinGroup(@PathParam("groupId") String groupId) {
auth.users().requireManage(user);
auth.users().requireManageGroupMembership(user);
GroupModel group = session.realms().getGroupById(groupId, realm);
if (group == null) {
throw new NotFoundException("Group not found");
}
//auth.groups().requireManageMembers(group);
auth.groups().requireManageMembership(group);
if (!user.isMemberOf(group)){
user.joinGroup(group);
adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();

View file

@ -25,6 +25,8 @@ import org.keycloak.services.resources.admin.AdminAuth;
public interface AdminPermissionEvaluator {
RealmPermissionEvaluator realm();
void requireAnyAdminRole();
AdminAuth adminAuth();
RolePermissionEvaluator roles();

View file

@ -35,6 +35,10 @@ public class AdminPermissions {
return new MgmtPermissions(session, realm, adminsRealm, admin);
}
public static RealmsPermissionEvaluator realms(KeycloakSession session, AdminAuth auth) {
return new MgmtPermissions(session, auth);
}
public static AdminPermissionManagement management(KeycloakSession session, RealmModel realm) {
return new MgmtPermissions(session, realm);
}

View file

@ -115,16 +115,12 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
String managePermissionName = getManagePermissionName(client);
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
if (managePermission == null) {
RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_CLIENTS);
Policy manageClientsPolicy = root.roles().rolePolicy(server, role);
Helper.addScopePermission(authz, server, managePermissionName, resource, manageScope, manageClientsPolicy);
Helper.addEmptyScopePermission(authz, server, managePermissionName, resource, manageScope);
}
String viewPermissionName = getViewPermissionName(client);
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
if (viewPermission == null) {
RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.VIEW_CLIENTS);
Policy viewClientsPolicy = root.roles().rolePolicy(server, role);
Helper.addScopePermission(authz, server, viewPermissionName, resource, viewScope, viewClientsPolicy);
Helper.addEmptyScopePermission(authz, server, viewPermissionName, resource, viewScope);
}
String mapRolePermissionName = getMapRolesPermissionName(client);
Policy mapRolePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRolePermissionName, server.getId());
@ -216,7 +212,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
throw new ForbiddenException();
}
}
public boolean canManageClientDefault() {
public boolean canManageClientsDefault() {
return root.hasOneAdminRole(AdminRoles.MANAGE_CLIENTS);
}
public boolean canViewClientDefault() {
@ -225,7 +221,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
@Override
public boolean canManage() {
return canManageClientDefault();
return canManageClientsDefault();
}
@Override
@ -236,7 +232,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
}
@Override
public boolean canView() {
return canManageClientDefault() || canViewClientDefault();
return canManageClientsDefault() || canViewClientDefault();
}
@Override
@ -269,25 +265,26 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
@Override
public boolean canManage(ClientModel client) {
if (canManageClientsDefault()) return true;
if (!root.isAdminSameRealm()) {
return canManage();
return false;
}
ResourceServer server = resourceServer(client);
if (server == null) return canManage();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
if (resource == null) return canManage();
if (resource == null) return false;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getManagePermissionName(client), server.getId());
if (policy == null) {
return canManage();
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canManage();
return false;
}
Scope scope = manageScope(server);
@ -303,25 +300,30 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
@Override
public boolean canView(ClientModel client) {
return hasView(client) || canManage(client);
}
private boolean hasView(ClientModel client) {
if (canView()) return true;
if (!root.isAdminSameRealm()) {
return canView();
return false;
}
ResourceServer server = resourceServer(client);
if (server == null) return canView();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
if (resource == null) return canView();
if (resource == null) return false;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getViewPermissionName(client), server.getId());
if (policy == null) {
return canView();
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canView();
return false;
}
Scope scope = viewScope(server);
@ -344,7 +346,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
@Override
public boolean canManageTemplates() {
return canManageClientDefault();
return canManageClientsDefault();
}
@Override
@ -362,7 +364,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
@Override
public boolean canManage(ClientTemplateModel template) {
return canManageClientDefault();
return canManageClientsDefault();
}
@Override

View file

@ -53,5 +53,9 @@ public interface GroupPermissionEvaluator {
void requireManageMembers(GroupModel group);
boolean canManageMembership(GroupModel group);
void requireManageMembership(GroupModel group);
Map<String, Boolean> getAccess(GroupModel group);
}

View file

@ -33,10 +33,14 @@ public interface GroupPermissionManagement {
Policy viewMembersPermission(GroupModel group);
Policy manageMembersPermission(GroupModel group);
Policy manageMembershipPermission(GroupModel group);
Policy viewPermission(GroupModel group);
Policy managePermission(GroupModel group);
Resource resource(GroupModel group);
Map<String, String> getPermissions(GroupModel group);
}

View file

@ -41,6 +41,7 @@ import java.util.Set;
class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManagement {
private static final Logger logger = Logger.getLogger(GroupPermissions.class);
public static final String MAP_ROLE_SCOPE = "map-role";
public static final String MANAGE_MEMBERSHIP_SCOPE = "manage.membership";
public static final String MANAGE_MEMBERS_SCOPE = "manage.members";
public static final String VIEW_MEMBERS_SCOPE = "view.members";
protected final KeycloakSession session;
@ -68,6 +69,10 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
return "manage.members.permission.group." + group.getId();
}
public static String getManageMembershipPermissionGroup(GroupModel group) {
return "manage.membership.permission.group." + group.getId();
}
public static String getGroupSuffix(GroupModel group) {
return ModelToRepresentation.buildGroupPath(group).replace('/', '.');
}
@ -88,6 +93,7 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
Scope viewScope = root.realmViewScope();
Scope manageMembersScope = root.initializeRealmScope(MANAGE_MEMBERS_SCOPE);
Scope viewMembersScope = root.initializeRealmScope(VIEW_MEMBERS_SCOPE);
Scope manageMembershipScope = root.initializeRealmScope(MANAGE_MEMBERSHIP_SCOPE);
String groupResourceName = getGroupResourceName(group);
Resource groupResource = authz.getStoreFactory().getResourceStore().findByName(groupResourceName, server.getId());
@ -96,19 +102,19 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
Set<Scope> scopeset = new HashSet<>();
scopeset.add(manageScope);
scopeset.add(viewScope);
scopeset.add(manageMembershipScope);
scopeset.add(manageMembersScope);
groupResource.updateScopes(scopeset);
}
String managePermissionName = getManagePermissionGroup(group);
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
if (managePermission == null) {
Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
Helper.addScopePermission(authz, server, managePermissionName, groupResource, manageScope, manageUsersPolicy);
Helper.addEmptyScopePermission(authz, server, managePermissionName, groupResource, manageScope);
}
String viewPermissionName = getViewPermissionGroup(group);
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
if (viewPermission == null) {
Policy viewUsersPolicy = root.roles().viewUsersPolicy(server);
Helper.addScopePermission(authz, server, viewPermissionName, groupResource, viewScope, viewUsersPolicy);
Helper.addEmptyScopePermission(authz, server, viewPermissionName, groupResource, viewScope);
}
String manageMembersPermissionName = getManageMembersPermissionGroup(group);
Policy manageMembersPermission = authz.getStoreFactory().getPolicyStore().findByName(manageMembersPermissionName, server.getId());
@ -120,6 +126,12 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
if (viewMembersPermission == null) {
Helper.addEmptyScopePermission(authz, server, viewMembersPermissionName, groupResource, viewMembersScope);
}
String manageMembershipPermissionName = getManageMembershipPermissionGroup(group);
Policy manageMembershipPermission = authz.getStoreFactory().getPolicyStore().findByName(manageMembershipPermissionName, server.getId());
if (manageMembershipPermission == null) {
Helper.addEmptyScopePermission(authz, server, manageMembershipPermissionName, groupResource, manageMembershipScope);
}
}
@Override
@ -199,6 +211,14 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
return authz.getStoreFactory().getPolicyStore().findByName(manageMembersPermissionName, server.getId());
}
@Override
public Policy manageMembershipPermission(GroupModel group) {
ResourceServer server = root.realmResourceServer();
if (server == null) return null;
String manageMembershipPermissionName = getManageMembershipPermissionGroup(group);
return authz.getStoreFactory().getPolicyStore().findByName(manageMembershipPermissionName, server.getId());
}
@Override
public Policy viewPermission(GroupModel group) {
ResourceServer server = root.realmResourceServer();
@ -231,6 +251,7 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission(group).getId());
scopes.put(MANAGE_MEMBERS_SCOPE, manageMembersPermission(group).getId());
scopes.put(VIEW_MEMBERS_SCOPE, viewMembersPermission(group).getId());
scopes.put(MANAGE_MEMBERSHIP_SCOPE, manageMembershipPermission(group).getId());
return scopes;
}
@ -239,25 +260,26 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
@Override
public boolean canManage(GroupModel group) {
if (canManage()) return true;
if (!root.isAdminSameRealm()) {
return canManage();
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return canManage();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return canManage();
if (resource == null) return false;
Policy policy = managePermission(group);
if (policy == null) {
return canManage();
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canManage();
return false;
}
Scope scope = root.realmManageScope();
@ -272,25 +294,31 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
}
@Override
public boolean canView(GroupModel group) {
return hasView(group) || canManage(group);
}
private boolean hasView(GroupModel group) {
if (canView()) return true;
if (!root.isAdminSameRealm()) {
return canView();
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return canView();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return canView();
if (resource == null) return false;
Policy policy = viewPermission(group);
if (policy == null) {
return canView();
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then abort
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canView();
return false;
}
Scope scope = root.realmViewScope();
@ -335,25 +363,27 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
}
private boolean canViewMembersEvaluation(GroupModel group) {
if (root.users().canView()) return true;
if (!root.isAdminSameRealm()) {
return root.users().canView();
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return root.users().canView();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return root.users().canView();
if (resource == null) return false;
Policy policy = viewMembersPermission(group);
if (policy == null) {
return root.users().canView();
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return root.users().canView();
return false;
}
Scope scope = authz.getStoreFactory().getScopeStore().findByName(VIEW_MEMBERS_SCOPE, server.getId());
@ -372,25 +402,27 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
@Override
public boolean canManageMembers(GroupModel group) {
if (root.users().canManage()) return true;
if (!root.isAdminSameRealm()) {
return root.users().canManage();
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return root.users().canManage();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return root.users().canManage();
if (resource == null) return false;
Policy policy = manageMembersPermission(group);
if (policy == null) {
return root.users().canManage();
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return root.users().canManage();
return false;
}
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MANAGE_MEMBERS_SCOPE, server.getId());
@ -404,11 +436,48 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
}
}
@Override
public boolean canManageMembership(GroupModel group) {
if (canManage(group)) return true;
if (!root.isAdminSameRealm()) {
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
if (resource == null) return false;
Policy policy = manageMembershipPermission(group);
if (policy == null) {
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return false;
}
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MANAGE_MEMBERSHIP_SCOPE, server.getId());
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireManageMembership(GroupModel group) {
if (!canManageMembership(group)) {
throw new ForbiddenException();
}
}
@Override
public Map<String, Boolean> getAccess(GroupModel group) {
Map<String, Boolean> map = new HashMap<>();
map.put("view", canView(group));
map.put("manage", canManage(group));
map.put("manageMembership", canManageMembership(group));
return map;
}

View file

@ -40,6 +40,7 @@ import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.RealmManager;
@ -51,7 +52,7 @@ import java.util.List;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManagement {
class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManagement, RealmsPermissionEvaluator {
private static final Logger logger = Logger.getLogger(MgmtPermissions.class);
protected RealmModel realm;
@ -85,7 +86,21 @@ class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManage
&& !auth.getRealm().equals(new RealmManager(session).getKeycloakAdminstrationRealm())) {
throw new ForbiddenException();
}
if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)) {
if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)
|| auth.getClient().getClientId().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
this.identity = new UserModelIdentity(auth.getRealm(), auth.getUser());
} else {
this.identity = new KeycloakIdentity(auth.getToken(), session);
}
}
MgmtPermissions(KeycloakSession session, AdminAuth auth) {
this.session = session;
this.auth = auth;
this.admin = auth.getUser();
this.adminsRealm = auth.getRealm();
if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)
|| auth.getClient().getClientId().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
this.identity = new UserModelIdentity(auth.getRealm(), auth.getUser());
} else {
@ -117,17 +132,36 @@ class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManage
@Override
public void requireAnyAdminRole() {
if (!hasAnyAdminRole()) {
throw new ForbiddenException();
}
}
public boolean hasAnyAdminRole() {
return hasOneAdminRole(AdminRoles.ALL_REALM_ROLES);
}
public boolean hasAnyAdminRole(RealmModel realm) {
return hasOneAdminRole(realm, AdminRoles.ALL_REALM_ROLES);
}
public boolean hasOneAdminRole(String... adminRoles) {
String clientId;
RealmModel realm = this.realm;
return hasOneAdminRole(realm, adminRoles);
}
public boolean hasOneAdminRole(RealmModel realm, String... adminRoles) {
String clientId;
RealmManager realmManager = new RealmManager(session);
if (adminsRealm.equals(realmManager.getKeycloakAdminstrationRealm())) {
clientId = realm.getMasterAdminClient().getClientId();
} else if (adminsRealm.equals(realm)) {
clientId = realm.getClientByClientId(realmManager.getRealmAdminClientId(realm)).getClientId();
} else {
clientId = realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())).getClientId();
return false;
}
for (String adminRole : adminRoles) {
if (identity.hasClientRole(clientId, adminRole)) return true;
@ -136,7 +170,6 @@ class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManage
}
public boolean isAdminSameRealm() {
return auth == null || realm.getId().equals(auth.getRealm().getId());
}
@ -274,6 +307,33 @@ class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManage
}
}
@Override
public boolean canView(RealmModel realm) {
return hasOneAdminRole(realm, AdminRoles.VIEW_REALM, AdminRoles.MANAGE_REALM);
}
@Override
public boolean isAdmin(RealmModel realm) {
return hasAnyAdminRole(realm);
}
@Override
public boolean canCreateRealm() {
RealmManager realmManager = new RealmManager(session);
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
return false;
}
return identity.hasRealmRole(AdminRoles.CREATE_REALM);
}
@Override
public void requireCreateRealm() {
if (!canCreateRealm()) {
throw new ForbiddenException();
}
}
}

View file

@ -16,12 +16,14 @@
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.models.RealmModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface RealmPermissionEvaluator {
boolean canListRealm();
boolean canListRealms();
void requireViewRealmNameList();

View file

@ -76,17 +76,18 @@ class RealmPermissions implements RealmPermissionEvaluator {
}
@Override
public boolean canListRealm() {
public boolean canListRealms() {
return root.hasAnyAdminRole();
}
@Override
public void requireViewRealmNameList() {
if (!canListRealm()) {
if (!canListRealms()) {
throw new ForbiddenException();
}
}
@Override
public boolean canManageRealm() {
return canManageRealmDefault();

View file

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

View file

@ -69,10 +69,15 @@ class RolePermissions implements RolePermissionEvaluator, RolePermissionManageme
} else {
ResourceServer server = resourceServer(role);
if (server == null) return;
Policy policy = mapRolePermission(role);
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
policy = mapClientScopePermission(role);
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
policy = mapCompositePermission(role);
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), server.getId());
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
}
}
@ -140,20 +145,22 @@ class RolePermissions implements RolePermissionEvaluator, RolePermissionManageme
*/
@Override
public boolean canMapRole(RoleModel role) {
if (root.users().canManageDefault()) return true;
if (!root.isAdminSameRealm()) {
return root.users().canManageDefault();
return false;
}
if (role.getContainer() instanceof ClientModel) {
if (root.clients().canMapRoles((ClientModel)role.getContainer())) return true;
}
if (!isPermissionsEnabled(role)){
return root.users().canManageDefault();
return false;
}
ResourceServer resourceServer = getResourceServer(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), resourceServer.getId());
if (policy.getAssociatedPolicies().isEmpty()) {
return root.users().canManageDefault(); // if no policies applied, just do default
return false;
}
Resource roleResource = resource(role);
@ -216,20 +223,22 @@ class RolePermissions implements RolePermissionEvaluator, RolePermissionManageme
@Override
public boolean canMapComposite(RoleModel role) {
if (canManageDefault(role)) return true;
if (!root.isAdminSameRealm()) {
return canManage(role);
return false;
}
if (role.getContainer() instanceof ClientModel) {
if (root.clients().canMapCompositeRoles((ClientModel)role.getContainer())) return true;
}
if (!isPermissionsEnabled(role)){
return canManage(role);
return false;
}
ResourceServer resourceServer = getResourceServer(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapCompositePermissionName(role), resourceServer.getId());
if (policy.getAssociatedPolicies().isEmpty()) {
return canManage(role);
return false;
}
Resource roleResource = resource(role);
@ -248,20 +257,21 @@ class RolePermissions implements RolePermissionEvaluator, RolePermissionManageme
@Override
public boolean canMapClientScope(RoleModel role) {
if (root.clients().canManageClientsDefault()) return true;
if (!root.isAdminSameRealm()) {
return root.clients().canManage();
return false;
}
if (role.getContainer() instanceof ClientModel) {
if (root.clients().canMapClientScopeRoles((ClientModel)role.getContainer())) return true;
}
if (!isPermissionsEnabled(role)){
return root.clients().canManage();
return false;
}
ResourceServer resourceServer = getResourceServer(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapClientScopePermissionName(role), resourceServer.getId());
if (policy.getAssociatedPolicies().isEmpty()) {
return root.clients().canManage();
return false;
}
Resource roleResource = resource(role);
@ -288,6 +298,16 @@ class RolePermissions implements RolePermissionEvaluator, RolePermissionManageme
return false;
}
public boolean canManageDefault(RoleModel role) {
if (role.getContainer() instanceof RealmModel) {
return root.realm().canManageRealmDefault();
} else if (role.getContainer() instanceof ClientModel) {
ClientModel client = (ClientModel)role.getContainer();
return root.clients().canManageClientsDefault();
}
return false;
}
@Override
public void requireManage(RoleModel role) {
if (!canManage(role)) {
@ -375,25 +395,15 @@ class RolePermissions implements RolePermissionEvaluator, RolePermissionManageme
Resource resource = authz.getStoreFactory().getResourceStore().create(getRoleResourceName(role), server, server.getClientId());
resource.setType("Role");
Scope mapRoleScope = getMapRoleScope(server);
Policy policy = manageUsersPolicy(server);
Policy mapRolePermission = Helper.addScopePermission(authz, server, getMapRolePermissionName(role), resource, mapRoleScope, policy);
Policy mapRolePermission = Helper.addEmptyScopePermission(authz, server, getMapRolePermissionName(role), resource, mapRoleScope);
mapRolePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
Scope mapClientScope = getMapClientScope(server);
RoleModel mngClients = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_CLIENTS);
Policy mngClientsPolicy = rolePolicy(server, mngClients);
Policy mapClientScopePermission = Helper.addScopePermission(authz, server, getMapClientScopePermissionName(role), resource, mapClientScope, mngClientsPolicy);
Policy mapClientScopePermission = Helper.addEmptyScopePermission(authz, server, getMapClientScopePermissionName(role), resource, mapClientScope);
mapClientScopePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
Scope mapCompositeScope = getMapCompositeScope(server);
if (role.getContainer() instanceof RealmModel) {
RoleModel mngRealm = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_REALM);
policy = rolePolicy(server, mngRealm);
} else {
policy = mngClientsPolicy;
}
Policy mapCompositePermission = Helper.addScopePermission(authz, server, getMapCompositePermissionName(role), resource, mapCompositeScope, policy);
Policy mapCompositePermission = Helper.addEmptyScopePermission(authz, server, getMapCompositePermissionName(role), resource, mapCompositeScope);
mapCompositePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
return resource;
}

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.authorization.model.Policy;
import org.keycloak.models.UserModel;
import java.util.Map;
@ -25,7 +26,7 @@ import java.util.Map;
* @version $Revision: 1 $
*/
public interface UserPermissionEvaluator {
boolean canManage();
boolean canManage();
void requireManage();
@ -51,4 +52,12 @@ public interface UserPermissionEvaluator {
void requireImpersonate(UserModel user);
Map<String, Boolean> getAccess(UserModel user);
boolean canMapRoles(UserModel user);
void requireMapRoles(UserModel user);
boolean canManageGroupMembership(UserModel user);
void requireManageGroupMembership(UserModel user);
}

View file

@ -38,4 +38,10 @@ public interface UserPermissionManagement {
Policy managePermission();
Policy viewPermission();
Policy manageGroupMembershipPermission();
Policy mapRolesPermission();
Policy impersonatePermission();
}

View file

@ -45,6 +45,12 @@ import java.util.Set;
*/
class UserPermissions implements UserPermissionEvaluator, UserPermissionManagement {
private static final Logger logger = Logger.getLogger(UserPermissions.class);
public static final String MAP_ROLES_SCOPE="map-roles";
public static final String IMPERSONATE_SCOPE="impersonate";
public static final String MANAGE_GROUP_MEMBERSHIP_SCOPE="manage-group-membership";
public static final String MAP_ROLES_PERMISSION_USERS = "map-roles.permission.users";
public static final String IMPERSONATE_PERMISSION_USERS = "impersonate.permission.users";
public static final String MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS = "manage-group-membership.permission.users";
public static final String MANAGE_PERMISSION_USERS = "manage.permission.users";
public static final String VIEW_PERMISSION_USERS = "view.permission.users";
public static final String USERS_RESOURCE = "Users";
@ -67,6 +73,9 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
ResourceServer server = root.realmResourceServer();
Scope manageScope = root.realmManageScope();
Scope viewScope = root.realmViewScope();
Scope mapRolesScope = root.initializeRealmScope(MAP_ROLES_SCOPE);
Scope impersonateScope = root.initializeRealmScope(IMPERSONATE_SCOPE);
Scope manageGroupMembershipScope = root.initializeRealmScope(MANAGE_GROUP_MEMBERSHIP_SCOPE);
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (usersResource == null) {
@ -74,17 +83,30 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
Set<Scope> scopeset = new HashSet<>();
scopeset.add(manageScope);
scopeset.add(viewScope);
scopeset.add(mapRolesScope);
scopeset.add(impersonateScope);
scopeset.add(manageGroupMembershipScope);
usersResource.updateScopes(scopeset);
}
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
if (managePermission == null) {
Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
Helper.addScopePermission(authz, server, MANAGE_PERMISSION_USERS, usersResource, manageScope, manageUsersPolicy);
Helper.addEmptyScopePermission(authz, server, MANAGE_PERMISSION_USERS, usersResource, manageScope);
}
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
if (viewPermission == null) {
Policy viewUsersPolicy = root.roles().viewUsersPolicy(server);
Helper.addScopePermission(authz, server, VIEW_PERMISSION_USERS, usersResource, viewScope, viewUsersPolicy);
Helper.addEmptyScopePermission(authz, server, VIEW_PERMISSION_USERS, usersResource, viewScope);
}
Policy mapRolesPermission = authz.getStoreFactory().getPolicyStore().findByName(MAP_ROLES_PERMISSION_USERS, server.getId());
if (mapRolesPermission == null) {
Helper.addEmptyScopePermission(authz, server, MAP_ROLES_PERMISSION_USERS, usersResource, mapRolesScope);
}
Policy membershipPermission = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
if (membershipPermission == null) {
Helper.addEmptyScopePermission(authz, server, MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, usersResource, manageGroupMembershipScope);
}
Policy impersonatePermission = authz.getStoreFactory().getPolicyStore().findByName(IMPERSONATE_PERMISSION_USERS, server.getId());
if (impersonatePermission == null) {
Helper.addEmptyScopePermission(authz, server, IMPERSONATE_PERMISSION_USERS, usersResource, impersonateScope);
}
}
@ -93,6 +115,9 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
Map<String, String> scopes = new HashMap<>();
scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission().getId());
scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission().getId());
scopes.put(MAP_ROLES_SCOPE, mapRolesPermission().getId());
scopes.put(MANAGE_GROUP_MEMBERSHIP_SCOPE, manageGroupMembershipPermission().getId());
scopes.put(IMPERSONATE_SCOPE, impersonatePermission().getId());
return scopes;
}
@ -117,7 +142,22 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
} else {
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (server == null) return;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
Policy policy = managePermission();
if (policy == null) {
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
}
policy = viewPermission();
if (policy == null) {
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
}
policy = mapRolesPermission();
if (policy == null) {
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
}
policy = manageGroupMembershipPermission();
if (policy == null) {
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
@ -153,6 +193,25 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
return authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
}
@Override
public Policy manageGroupMembershipPermission() {
ResourceServer server = root.realmResourceServer();
return authz.getStoreFactory().getPolicyStore().findByName(MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
}
@Override
public Policy mapRolesPermission() {
ResourceServer server = root.realmResourceServer();
return authz.getStoreFactory().getPolicyStore().findByName(MAP_ROLES_PERMISSION_USERS, server.getId());
}
@Override
public Policy impersonatePermission() {
ResourceServer server = root.realmResourceServer();
return authz.getStoreFactory().getPolicyStore().findByName(IMPERSONATE_PERMISSION_USERS, server.getId());
}
/**
@ -170,25 +229,26 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
*/
@Override
public boolean canManage() {
if (canManageDefault()) return true;
if (!root.isAdminSameRealm()) {
return canManageDefault();
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return canManageDefault();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return canManageDefault();
if (resource == null) return false;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
if (policy == null) {
return canManageDefault();
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return canManageDefault();
return false;
}
Scope scope = root.realmManageScope();
@ -321,14 +381,15 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
*/
@Override
public boolean canView() {
if (canViewDefault()) return true;
if (!root.isAdminSameRealm()) {
return canViewDefault();
return false;
}
return hasViewPermission() || canManage();
}
public boolean hasViewPermission() {
private boolean hasViewPermission() {
ResourceServer server = root.realmResourceServer();
if (server == null) return canViewDefault();
@ -382,7 +443,32 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
@Override
public boolean canImpersonate(UserModel user) {
return root.hasOneAdminRole(ImpersonationConstants.IMPERSONATION_ROLE);
if (root.hasOneAdminRole(ImpersonationConstants.IMPERSONATION_ROLE)) return true;
if (!root.isAdminSameRealm()) {
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return false;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(IMPERSONATE_PERMISSION_USERS, server.getId());
if (policy == null) {
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return false;
}
Scope scope = root.realmScope(IMPERSONATE_SCOPE);
return root.evaluatePermission(resource, scope, server);
}
@Override
@ -397,9 +483,90 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
Map<String, Boolean> map = new HashMap<>();
map.put("view", canView(user));
map.put("manage", canManage(user));
map.put("mapRoles", canMapRoles(user));
map.put("manageGroupMembership", canManageGroupMembership(user));
map.put("impersonate", canImpersonate(user));
return map;
}
@Override
public boolean canMapRoles(UserModel user) {
if (canManage(user)) return true;
if (!root.isAdminSameRealm()) {
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return false;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MAP_ROLES_PERMISSION_USERS, server.getId());
if (policy == null) {
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return false;
}
Scope scope = root.realmScope(MAP_ROLES_SCOPE);
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireMapRoles(UserModel user) {
if (!canMapRoles(user)) {
throw new ForbiddenException();
}
}
@Override
public boolean canManageGroupMembership(UserModel user) {
if (canManage(user)) return true;
if (!root.isAdminSameRealm()) {
return false;
}
ResourceServer server = root.realmResourceServer();
if (server == null) return false;
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
if (resource == null) return false;
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
if (policy == null) {
return false;
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
// if no policies attached to permission then just do default behavior
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
return false;
}
Scope scope = root.realmScope(MANAGE_GROUP_MEMBERSHIP_SCOPE);
return root.evaluatePermission(resource, scope, server);
}
@Override
public void requireManageGroupMembership(UserModel user) {
if (!canManageGroupMembership(user)) {
throw new ForbiddenException();
}
}

View file

@ -66,6 +66,43 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
testRealmRep.setEnabled(true);
testRealms.add(testRealmRep);
}
public static void setupDemo(KeycloakSession session) {
RealmModel realm = session.realms().getRealmByName(TEST);
ClientModel client = realm.addClient("sales-pipeline-application");
RoleModel clientAdmin = client.addRole("admin");
client.addRole("leader-creator");
client.addRole("viewLeads");
ClientModel client2 = realm.addClient("market-analysis-application");
RoleModel client2Admin = client2.addRole("admin");
client2.addRole("market-manager");
client2.addRole("viewMarkets");
GroupModel sales = realm.createGroup("sales");
RoleModel salesAppsAdminRole = realm.addRole("sales-apps-admin");
salesAppsAdminRole.addCompositeRole(clientAdmin);
salesAppsAdminRole.addCompositeRole(client2Admin);
UserModel admin = session.users().addUser(realm, "salesManager");
admin.setEnabled(true);
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
admin = session.users().addUser(realm, "sales-group-admin");
admin.setEnabled(true);
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
admin = session.users().addUser(realm, "sales-it");
admin.setEnabled(true);
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
admin = session.users().addUser(realm, "sales-pipeline-admin");
admin.setEnabled(true);
session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
UserModel user = session.users().addUser(realm, "salesman");
user.setEnabled(true);
user.joinGroup(sales);
user = session.users().addUser(realm, "saleswoman");
user.setEnabled(true);
}
public static void setupPolices(KeycloakSession session) {
RealmModel realm = session.realms().getRealmByName(TEST);
@ -304,9 +341,14 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
protected boolean isImportAfterEachMethod() {
return true;
}
//@Test
public void testDemo() throws Exception {
testingClient.server().run(FineGrainAdminUnitTest::setupDemo);
Thread.sleep(1000000000);
}
@Test
//@Test
public void testUI() throws Exception {
testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
testingClient.server().run(FineGrainAdminUnitTest::setupUsers);

View file

@ -717,7 +717,7 @@ public class PermissionsTest extends AbstractKeycloakTest {
public void invoke(RealmResource realm) {
realm.clientTemplates().findAll();
}
}, Resource.CLIENT, false);
}, Resource.CLIENT, false, true);
invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) {
ClientTemplateRepresentation template = new ClientTemplateRepresentation();

View file

@ -29,7 +29,7 @@ log4j.appender.testsuite.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%C{1}]
keycloak.logging.level=info
log4j.logger.org.keycloak=${keycloak.logging.level}
log4j.logger.org.jboss.resteasy.resteasy_jaxrs.i18n=off
#log4j.logger.org.jboss.resteasy.resteasy_jaxrs.i18n=off
#log4j.logger.org.keycloak.keys.DefaultKeyManager=trace
#log4j.logger.org.keycloak.services.managers.AuthenticationManager=trace
@ -62,7 +62,7 @@ log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=de
log4j.logger.org.xnio=off
log4j.logger.org.hibernate=off
log4j.logger.org.jboss.resteasy=warn
log4j.logger.org.jboss.resteasy=info
log4j.logger.org.apache.directory.api=warn
log4j.logger.org.apache.directory.server.core=warn

View file

@ -2394,6 +2394,7 @@ module.controller('ClientRolePermissionsCtrl', function($scope, $http, $route, $
$scope.permissions = data;
});
$scope.setEnabled = function() {
console.log('perssions enabled: ' + $scope.permissions.enabled);
var param = { enabled: $scope.permissions.enabled};
$scope.permissions = RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param);
};

View file

@ -6,7 +6,7 @@
<kc-tabs-group></kc-tabs-group>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageUsers">
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!group.access.manage">
<table class="table table-striped table-bordered">
<thead>
<tr>
@ -29,7 +29,7 @@
</tbody>
</table>
<div class="form-group" data-ng-show="access.manageUsers">
<div class="form-group" data-ng-show="group.access.manage">
<div class="col-md-12">
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>

View file

@ -16,7 +16,7 @@
</div>
</fieldset>
<div class="form-group" data-ng-show="access.manageUsers">
<div class="form-group" data-ng-show="group.access.manage">
<div class="col-md-10 col-md-offset-2">
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
<button kc-reset data-ng-disabled="!changed" data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>

View file

@ -7,7 +7,7 @@
<kc-tabs-group></kc-tabs-group>
<form class="form-horizontal" name="realmForm" novalidate>
<div class="form-group" kc-read-only="!access.manageUsers">
<div class="form-group" kc-read-only="!group.access.manage">
<label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
<div class="col-md-10">
@ -54,7 +54,7 @@
<span>{{:: 'client-roles' | translate}}</span>
<select class="form-control" id="clients" name="clients" ng-change="changeClient()" ng-model="targetClient" ng-options="a.clientId for a in clients | orderBy:'clientId'" ng-disabled="false"></select>
</label>
<div class="col-md-10" kc-read-only="!access.manageUsers">
<div class="col-md-10" kc-read-only="!group.access.manage">
<div class="row" data-ng-hide="targetClient">
<div class="col-md-4"><span class="text-muted">{{:: 'select-client-to-view-roles' | translate}}</span></div>
</div>

View file

@ -7,7 +7,7 @@
<kc-tabs-user></kc-tabs-user>
<form class="form-horizontal" name="realmForm" novalidate>
<div class="form-group" kc-read-only="!access.manageUsers">
<div class="form-group" kc-read-only="!user.access.mapRoles">
<label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
<div class="col-md-10">
@ -54,7 +54,7 @@
<span>{{:: 'client-roles' | translate}}</span>
<select class="form-control" id="clients" name="clients" ng-change="changeClient()" ng-model="targetClient" ng-options="a.clientId for a in clients | orderBy:'clientId'" ng-disabled="false"></select>
</label>
<div class="col-md-10" kc-read-only="!access.manageUsers">
<div class="col-md-10" kc-read-only="!user.access.mapRoles">
<div class="row" data-ng-hide="targetClient">
<div class="col-md-4"><span class="text-muted">{{:: 'select-client-to-view-roles' | translate}}</span></div>
</div>

View file

@ -138,7 +138,7 @@
<button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
</div>
<div class="col-md-10 col-md-offset-2" data-ng-show="!create && !user.access.manage">
<div class="col-md-10 col-md-offset-2" data-ng-show="!create && user.access.manage">
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
</div>

View file

@ -7,7 +7,7 @@
<kc-tabs-user></kc-tabs-user>
<form class="form-horizontal" name="realmForm" novalidate>
<div class="form-group" kc-read-only="!access.manageUsers">
<div class="form-group" kc-read-only="!user.access.manageGroupMembership">
<label class="col-md-1 control-label" class="control-label"></label>
<div class="col-md-8" >
@ -21,7 +21,7 @@
<label class="control-label">{{:: 'group-membership' | translate}}</label>
<kc-tooltip>{{:: 'group-membership.tooltip' | translate}}</kc-tooltip>
<div class="pull-right" data-ng-show="access.manageUsers">
<div class="pull-right" data-ng-show="user.access.manageGroupMembership">
<button id="leaveGroups" class="btn btn-default" ng-click="leaveGroup()">{{:: 'leave' | translate}}</button>
</div>
</div>
@ -53,7 +53,7 @@
<label class="control-label">{{:: 'available-groups' | translate}}</label>
<kc-tooltip>{{:: 'membership.available-groups.tooltip' | translate}}</kc-tooltip>
<div class="pull-right" data-ng-show="access.manageUsers">
<div class="pull-right" data-ng-show="user.access.manageGroupMembership">
<button id="joinGroup" class="btn btn-default" ng-click="joinGroup()">{{:: 'join' | translate}}</button>
</div>
</div>