keycloak-aplcache
Changes
services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionManagement.java 17(+17 -0)
services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissions.java 89(+67 -22)
services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionManagement.java 5(+5 -0)
services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java 36(+30 -6)
services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissions.java 6(+3 -3)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java 6(+5 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java 21(+10 -11)
themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-permissions.html 39(+39 -0)
themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html 3(+1 -2)
themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/group-permissions.html 39(+39 -0)
themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html 2(+1 -1)
Details
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index 58ae623..36362cb 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -31,6 +31,7 @@ import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
@@ -41,6 +42,7 @@ import org.keycloak.protocol.ClientInstallationProvider;
import org.keycloak.representations.adapters.action.GlobalRequestResult;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.ManagementPermissionReference;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.services.ErrorResponse;
@@ -52,6 +54,8 @@ import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
import org.keycloak.services.validation.ClientValidator;
import org.keycloak.services.validation.PairwiseClientValidator;
import org.keycloak.services.validation.ValidationMessages;
@@ -536,4 +540,55 @@ public class ClientResource {
return resource;
}
+
+ /**
+ * Return object stating whether client Authorization permissions have been initialized or not and a reference
+ *
+ * @return
+ */
+ @Path("management/permissions")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @NoCache
+ public ManagementPermissionReference getManagementPermissions() {
+ auth.roles().requireView(client);
+
+ AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+ if (!permissions.clients().isPermissionsEnabled(client)) {
+ return new ManagementPermissionReference();
+ }
+ return toMgmtRef(client, permissions);
+ }
+
+ public static ManagementPermissionReference toMgmtRef(ClientModel client, AdminPermissionManagement permissions) {
+ ManagementPermissionReference ref = new ManagementPermissionReference();
+ ref.setEnabled(true);
+ ref.setResource(permissions.clients().resource(client).getId());
+ ref.setScopePermissions(permissions.clients().getPermissions(client));
+ return ref;
+ }
+
+
+ /**
+ * Return object stating whether client Authorization permissions have been initialized or not and a reference
+ *
+ *
+ * @return initialized manage permissions reference
+ */
+ @Path("management/permissions")
+ @PUT
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @NoCache
+ public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
+ auth.clients().requireManage(client);
+ if (ref.isEnabled()) {
+ AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+ permissions.clients().setPermissionsEnabled(client, ref.isEnabled());
+ return toMgmtRef(client, permissions);
+ } else {
+ return new ManagementPermissionReference();
+ }
+ }
+
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
index d620560..41b91be 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
@@ -207,7 +207,7 @@ public class ClientsResource {
ClientModel clientModel = realm.getClientById(id);
if (clientModel == null) {
// we do this to make sure somebody can't phish ids
- if (!auth.clients().canList()) throw new NotFoundException("Could not find client");
+ if (auth.clients().canList()) throw new NotFoundException("Could not find client");
else throw new ForbiddenException();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java b/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
index a529a48..a5b7a6c 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
@@ -21,6 +21,7 @@ import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
@@ -28,6 +29,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.representations.idm.ManagementPermissionReference;
import org.keycloak.representations.idm.UserRepresentation;
import javax.ws.rs.Consumes;
@@ -50,6 +52,8 @@ import java.util.Map;
import java.util.Set;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
/**
* @resource Groups
@@ -214,4 +218,55 @@ public class GroupResource {
return results;
}
+ /**
+ * Return object stating whether client Authorization permissions have been initialized or not and a reference
+ *
+ * @return
+ */
+ @Path("management/permissions")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @NoCache
+ public ManagementPermissionReference getManagementPermissions() {
+ auth.groups().requireView(group);
+
+ AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+ if (!permissions.groups().isPermissionsEnabled(group)) {
+ return new ManagementPermissionReference();
+ }
+ return toMgmtRef(group, permissions);
+ }
+
+ public static ManagementPermissionReference toMgmtRef(GroupModel group, AdminPermissionManagement permissions) {
+ ManagementPermissionReference ref = new ManagementPermissionReference();
+ ref.setEnabled(true);
+ ref.setResource(permissions.groups().resource(group).getId());
+ ref.setScopePermissions(permissions.groups().getPermissions(group));
+ return ref;
+ }
+
+
+ /**
+ * Return object stating whether client Authorization permissions have been initialized or not and a reference
+ *
+ *
+ * @return initialized manage permissions reference
+ */
+ @Path("management/permissions")
+ @PUT
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @NoCache
+ public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
+ auth.groups().requireManage(group);
+ if (ref.isEnabled()) {
+ AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+ permissions.groups().setPermissionsEnabled(group, ref.isEnabled());
+ return toMgmtRef(group, permissions);
+ } else {
+ return new ManagementPermissionReference();
+ }
+ }
+
}
+
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionManagement.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionManagement.java
index 26ae951..d967443 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionManagement.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionManagement.java
@@ -17,21 +17,38 @@
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.ClientModel;
+import java.util.Map;
+
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface ClientPermissionManagement {
public static final String MAP_ROLES_SCOPE = "map-roles";
+ public static final String MAP_ROLES_CLIENT_SCOPE = "map-roles-client-scope";
+ public static final String MAP_ROLES_COMPOSITE_SCOPE = "map-roles-composite";
boolean isPermissionsEnabled(ClientModel client);
void setPermissionsEnabled(ClientModel client, boolean enable);
+ Resource resource(ClientModel client);
+
+ Map<String, String> getPermissions(ClientModel client);
+
Policy mapRolesPermission(ClientModel client);
+ Policy mapRolesClientScopePermission(ClientModel client);
+
+ Policy mapRolesCompositePermission(ClientModel client);
+
+ Policy managePermission(ClientModel client);
+
+ Policy viewPermission(ClientModel client);
+
ResourceServer resourceServer(ClientModel client);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissions.java
index 3118f7a..06fa5d8 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissions.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissions.java
@@ -30,7 +30,9 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.services.ForbiddenException;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
/**
@@ -67,11 +69,11 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
private String getMapRolesPermissionName(ClientModel client) {
return MAP_ROLES_SCOPE + ".permission.client." + client.getId();
}
- private String getMapRoleClientScopePermissionName(ClientModel client) {
- return RolePermissionManagement.MAP_ROLE_CLIENT_SCOPE_SCOPE + ".permission.client." + client.getId();
+ private String getMapRolesClientScopePermissionName(ClientModel client) {
+ return MAP_ROLES_CLIENT_SCOPE + ".permission.client." + client.getId();
}
- private String getMapRoleCompositePermissionName(ClientModel client) {
- return RolePermissionManagement.MAP_ROLE_COMPOSITE_SCOPE + ".permission.client." + client.getId();
+ private String getMapRolesCompositePermissionName(ClientModel client) {
+ return MAP_ROLES_COMPOSITE_SCOPE + ".permission.client." + client.getId();
}
private void initialize(ClientModel client) {
@@ -88,13 +90,13 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
if (mapRoleScope == null) {
mapRoleScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_SCOPE, server);
}
- Scope mapRoleClientScope = mapRoleClientScope(server);
+ Scope mapRoleClientScope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_CLIENT_SCOPE, server.getId());
if (mapRoleClientScope == null) {
- mapRoleClientScope = authz.getStoreFactory().getScopeStore().create(RolePermissionManagement.MAP_ROLE_CLIENT_SCOPE_SCOPE, server);
+ mapRoleClientScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_CLIENT_SCOPE, server);
}
- Scope mapRoleCompositeScope = mapRoleCompositeScope(server);
+ Scope mapRoleCompositeScope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_COMPOSITE_SCOPE, server.getId());
if (mapRoleCompositeScope == null) {
- mapRoleCompositeScope = authz.getStoreFactory().getScopeStore().create(RolePermissionManagement.MAP_ROLE_COMPOSITE_SCOPE, server);
+ mapRoleCompositeScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_COMPOSITE_SCOPE, server);
}
String resourceName = getResourceName(client);
@@ -129,12 +131,12 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
if (mapRolePermission == null) {
Helper.addEmptyScopePermission(authz, server, mapRolePermissionName, resource, mapRoleScope);
}
- String mapRoleClientScopePermissionName = getMapRoleClientScopePermissionName(client);
+ String mapRoleClientScopePermissionName = getMapRolesClientScopePermissionName(client);
Policy mapRoleClientScopePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRoleClientScopePermissionName, server.getId());
if (mapRoleClientScopePermission == null) {
Helper.addEmptyScopePermission(authz, server, mapRoleClientScopePermissionName, resource, mapRoleClientScope);
}
- String mapRoleCompositePermissionName = getMapRoleCompositePermissionName(client);
+ String mapRoleCompositePermissionName = getMapRolesCompositePermissionName(client);
Policy mapRoleCompositePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRoleCompositePermissionName, server.getId());
if (mapRoleCompositePermission == null) {
Helper.addEmptyScopePermission(authz, server, mapRoleCompositePermissionName, resource, mapRoleCompositeScope);
@@ -155,8 +157,8 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
deletePolicy(getManagePermissionName(client), client, server);
deletePolicy(getViewPermissionName(client), client, server);
deletePolicy(getMapRolesPermissionName(client), client, server);
- deletePolicy(getMapRoleClientScopePermissionName(client), client, server);
- deletePolicy(getMapRoleCompositePermissionName(client), client, server);
+ deletePolicy(getMapRolesClientScopePermissionName(client), client, server);
+ deletePolicy(getMapRolesCompositePermissionName(client), client, server);
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());;
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
}
@@ -190,12 +192,6 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
private Scope mapRolesScope(ResourceServer server) {
return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_SCOPE, server.getId());
}
- private Scope mapRoleClientScope(ResourceServer server) {
- return authz.getStoreFactory().getScopeStore().findByName(RolePermissionManagement.MAP_ROLE_CLIENT_SCOPE_SCOPE, server.getId());
- }
- private Scope mapRoleCompositeScope(ResourceServer server) {
- return authz.getStoreFactory().getScopeStore().findByName(RolePermissionManagement.MAP_ROLE_COMPOSITE_SCOPE, server.getId());
- }
@Override
public boolean canList() {
@@ -251,6 +247,27 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
}
@Override
+ public Resource resource(ClientModel client) {
+ ResourceServer server = resourceServer(client);
+ if (server == null) return null;
+ Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
+ if (resource == null) return null;
+ return resource;
+ }
+
+ @Override
+ public Map<String, String> getPermissions(ClientModel client) {
+ Map<String, String> scopes = new HashMap<>();
+ scopes.put(MAP_ROLES_SCOPE, mapRolesPermission(client).getId());
+ scopes.put(MAP_ROLES_CLIENT_SCOPE, mapRolesClientScopePermission(client).getId());
+ scopes.put(MAP_ROLES_COMPOSITE_SCOPE, mapRolesCompositePermission(client).getId());
+ scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission(client).getId());
+ scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission(client).getId());
+ return scopes;
+ }
+
+
+ @Override
public boolean canManage(ClientModel client) {
if (!root.isAdminSameRealm()) {
return canManage();
@@ -398,6 +415,34 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
}
@Override
+ public Policy mapRolesClientScopePermission(ClientModel client) {
+ ResourceServer server = resourceServer(client);
+ if (server == null) return null;
+ return authz.getStoreFactory().getPolicyStore().findByName(getMapRolesClientScopePermissionName(client), server.getId());
+ }
+
+ @Override
+ public Policy mapRolesCompositePermission(ClientModel client) {
+ ResourceServer server = resourceServer(client);
+ if (server == null) return null;
+ return authz.getStoreFactory().getPolicyStore().findByName(getMapRolesCompositePermissionName(client), server.getId());
+ }
+
+ @Override
+ public Policy managePermission(ClientModel client) {
+ ResourceServer server = resourceServer(client);
+ if (server == null) return null;
+ return authz.getStoreFactory().getPolicyStore().findByName(getManagePermissionName(client), server.getId());
+ }
+
+ @Override
+ public Policy viewPermission(ClientModel client) {
+ ResourceServer server = resourceServer(client);
+ if (server == null) return null;
+ return authz.getStoreFactory().getPolicyStore().findByName(getViewPermissionName(client), server.getId());
+ }
+
+ @Override
public ResourceServer resourceServer(ClientModel client) {
return authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
}
@@ -410,7 +455,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
if (resource == null) return false;
- Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleCompositePermissionName(client), server.getId());
+ Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolesCompositePermissionName(client), server.getId());
if (policy == null) {
return false;
}
@@ -421,7 +466,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
return false;
}
- Scope scope = mapRoleCompositeScope(server);
+ Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_COMPOSITE_SCOPE, server.getId());
return root.evaluatePermission(resource, scope, server);
}
@Override
@@ -432,7 +477,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
if (resource == null) return false;
- Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleClientScopePermissionName(client), server.getId());
+ Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolesClientScopePermissionName(client), server.getId());
if (policy == null) {
return false;
}
@@ -443,7 +488,7 @@ class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionMa
return false;
}
- Scope scope = mapRoleClientScope(server);
+ Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_CLIENT_SCOPE, server.getId());
return root.evaluatePermission(resource, scope, server);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionManagement.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionManagement.java
index 5f4097b..a3277ba 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionManagement.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionManagement.java
@@ -17,6 +17,7 @@
package org.keycloak.services.resources.admin.permissions;
import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
import org.keycloak.models.GroupModel;
import org.keycloak.models.RoleModel;
@@ -34,4 +35,8 @@ public interface GroupPermissionManagement {
Policy manageMembersPermission(GroupModel group);
Policy viewPermissionGroup(GroupModel group);
Policy managePermissionGroup(GroupModel group);
+
+ Resource resource(GroupModel group);
+
+ Map<String, String> getPermissions(GroupModel group);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java
index e1c0356..acf80c1 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java
@@ -23,13 +23,16 @@ import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.models.AdminRoles;
+import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.ForbiddenException;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
/**
@@ -54,16 +57,16 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
}
private static String getGroupResourceName(GroupModel group) {
- return "group.resource." + getGroupSuffix(group);
+ return "group.resource." + group.getId();
}
public static String getManagePermissionGroup(GroupModel group) {
- return "manage.permission.group." + getGroupSuffix(group);
+ return "manage.permission.group." + group.getId();
}
public static String getManageMembersPermissionGroup(GroupModel group) {
- return "manage.members.permission.group." + getGroupSuffix(group);
+ return "manage.members.permission.group." + group.getId();
}
public static String getGroupSuffix(GroupModel group) {
@@ -71,11 +74,11 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
}
public static String getViewPermissionGroup(GroupModel group) {
- return "view.permission.group." + getGroupSuffix(group);
+ return "view.permission.group." + group.getId();
}
public static String getViewMembersPermissionGroup(GroupModel group) {
- return "view.members.permission.group." + getGroupSuffix(group);
+ return "view.members.permission.group." + group.getId();
}
private void initialize(GroupModel group) {
@@ -102,7 +105,7 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
Helper.addScopePermission(authz, server, managePermissionName, groupResource, manageScope, manageUsersPolicy);
}
- String viewPermissionName = getManagePermissionGroup(group);
+ String viewPermissionName = getViewPermissionGroup(group);
Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
if (viewPermission == null) {
Policy viewUsersPolicy = root.roles().viewUsersPolicy(server);
@@ -213,6 +216,27 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
return authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
}
+ @Override
+ public Resource resource(GroupModel group) {
+ ResourceServer server = root.realmResourceServer();
+ if (server == null) return null;
+ Resource resource = authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
+ if (resource == null) return null;
+ return resource;
+ }
+
+ @Override
+ public Map<String, String> getPermissions(GroupModel group) {
+ Map<String, String> scopes = new HashMap<>();
+ scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermissionGroup(group).getId());
+ scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermissionGroup(group).getId());
+ scopes.put(MANAGE_MEMBERS_SCOPE, manageMembersPermission(group).getId());
+ scopes.put(VIEW_MEMBERS_SCOPE, viewMembersPermission(group).getId());
+ return scopes;
+ }
+
+
+
@Override
public boolean canManage(GroupModel group) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissions.java
index 5f666c6..83838de 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissions.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissions.java
@@ -141,19 +141,19 @@ class RolePermissions implements RolePermissionEvaluator, RolePermissionManageme
@Override
public boolean canMapRole(RoleModel role) {
if (!root.isAdminSameRealm()) {
- return root.users().canManage();
+ return root.users().canManageDefault();
}
if (role.getContainer() instanceof ClientModel) {
if (root.clients().canMapRoles((ClientModel)role.getContainer())) return true;
}
if (!isPermissionsEnabled(role)){
- return root.users().canManage();
+ return root.users().canManageDefault();
}
ResourceServer resourceServer = getResourceServer(role);
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), resourceServer.getId());
if (policy.getAssociatedPolicies().isEmpty()) {
- return root.users().canManage(); // if no policies applied, just do default
+ return root.users().canManageDefault(); // if no policies applied, just do default
}
Resource roleResource = resource(role);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
index 1601189..d6d2ad8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -175,7 +175,11 @@ public abstract class AbstractKeycloakTest {
// Cleanup objects
for (TestCleanup cleanup : testContext.getCleanups().values()) {
- if (cleanup != null) cleanup.executeCleanup();
+ try {
+ if (cleanup != null) cleanup.executeCleanup();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
testContext.getCleanups().clear();
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java
index 5d413d0..72f3df9 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java
@@ -282,7 +282,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
}
- //@Test
+ @Test
public void testUI() throws Exception {
testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
@@ -308,7 +308,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
realmRoleSet.add(realmRole);
RoleRepresentation realmRole2 = adminClient.realm(TEST).roles().get("realm-role2").toRepresentation();
List<RoleRepresentation> realmRole2Set = new LinkedList<>();
- realmRole2Set.add(realmRole);
+ realmRole2Set.add(realmRole2);
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<>();
@@ -395,18 +395,18 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
TEST, "groupManager", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
List<RoleRepresentation> roles = null;
realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
- roles = realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
+ roles = realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).listAll();
Assert.assertTrue(roles.stream().anyMatch((r) -> {
return r.getName().equals("client-role");
}));
- realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
+ realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
- roles = realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAvailable();
+ roles = realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().listAvailable();
Assert.assertEquals(roles.size(), 1);
- realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
- realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().remove(realmRoleSet);
+ realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().add(realmRoleSet);
+ realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().remove(realmRoleSet);
try {
- realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRole2Set);
+ realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().add(realmRole2Set);
Assert.fail("should fail with forbidden exception");
} catch (ClientErrorException e) {
Assert.assertEquals(e.getResponse().getStatus(), 403);
@@ -428,6 +428,8 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
TEST, "clientMapper", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
List<RoleRepresentation> roles = null;
+ roles = realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
+ Assert.assertTrue(roles.isEmpty());
realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
roles = realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
Assert.assertTrue(roles.stream().anyMatch((r) -> {
@@ -455,9 +457,6 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
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);
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 1dd53fa..11fe2c5 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -1306,7 +1306,8 @@ credential-reset-actions-timeout.tooltip=Maximum time before the action permit e
ldap-mappers=LDAP Mappers
create-ldap-mapper=Create LDAP mapper
map-role-mgmt-scope-description=Policies that decide if an admin can map this role to a user or group
-manage-mgmt-scope-description=Policies that decide if an admin can manage this resource or resources
+manage-authz-users-scope-description=Policies that decide if an admin can manage all users in the realm
+view-authz-users-scope-description=Policies that decide if an admin can view all users in realm
permissions-enabled-role=Permissions Enabled
permissions-enabled-role.tooltip=Whether or not to enable fine grain permissions for managing this role. Disabling will delete all current permissions that have been set up.
manage-permissions-role.tooltip=Fine grain permissions for managing roles. For example, you can define different policies for who is allowed to map a role.
@@ -1314,6 +1315,20 @@ lookup=Lookup
manage-permissions-users.tooltip=Fine grain permssions for managing all users in realm. You can define different policies for who is allowed to manage users in the realm.
permissions-enabled-users=Permissions Enabled
permissions-enabled-users.tooltip=Whether or not to enable fine grain permissions for managing users. Disabling will delete all current permissions that have been set up.
+manage-permissions-client.tooltip=Fine grain permssions for admins that want to manage this client or apply roles defined by this client.
+manage-permissions-group.tooltip=Fine grain permssions for admins that want to manage this group or the members of this group.
+manage-authz-group-scope-description=Policies that decide if an admin can manage this group
+view-authz-group-scope-description=Policies that decide if an admin can view this group
+view.members-authz-group-scope-description=Policies that decide if an admin can manage the members of this group
+manage.members-authz-group-scope-description=Policies that decide if an admin can view the members of this group
+manage-authz-client-scope-description=Policies that decide if an admin can manage this client
+view-authz-client-scope-description=Policies that decide if an admin can view this client
+map-roles-authz-client-scope-description=Policies that decide if an admin can map roles defined by this client
+map-roles-client-scope-authz-client-scope-description=Policies that decide if an admin can apply roles defined by this client to the client scope of another client
+map-roles-composite-authz-client-scope-description=Policies that decide if an admin can apply roles defined by this client as a composite to another role
+map-role-authz-role-scope-description=Policies that decide if an admin can map role this role to a user or group
+map-role-client-scope-authz-role-scope-description=Policies that decide if an admin can apply this role to the client scope of a client
+map-role-composite-authz-role-scope-description=Policies that decide if an admin can apply this role as a composite to another role
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js
index 455891d..047fa49 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js
@@ -424,6 +424,30 @@ module.config(['$routeProvider', function ($routeProvider) {
},
controller : 'UsersPermissionsCtrl'
})
+ .when('/realms/:realm/clients/:client/permissions', {
+ templateUrl : resourceUrl + '/partials/authz/mgmt/client-permissions.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ client : function(ClientLoader) {
+ return ClientLoader();
+ }
+ },
+ controller : 'ClientPermissionsCtrl'
+ })
+ .when('/realms/:realm/groups/:group/permissions', {
+ templateUrl : resourceUrl + '/partials/authz/mgmt/group-permissions.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ group : function(GroupLoader) {
+ return GroupLoader();
+ }
+ },
+ controller : 'GroupPermissionsCtrl'
+ })
;
}]);
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
index 5eb0ba2..37b4984 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
@@ -2419,3 +2419,35 @@ module.controller('UsersPermissionsCtrl', function($scope, $http, $route, $locat
});
+module.controller('ClientPermissionsCtrl', function($scope, $http, $route, $location, realm, client, ClientManagementPermissions, Notifications) {
+ $scope.client = client;
+ $scope.realm = realm;
+ ClientManagementPermissions.get({realm: realm.realm, client: client.id}, function(data) {
+ $scope.permissions = data;
+ });
+ $scope.setEnabled = function() {
+ var param = { enabled: $scope.permissions.enabled};
+ $scope.permissions = ClientManagementPermissions.update({realm: realm.realm, client: client.id}, param);
+ };
+
+
+});
+
+module.controller('GroupPermissionsCtrl', function($scope, $http, $route, $location, realm, group, GroupManagementPermissions, Client, Notifications) {
+ $scope.group = group;
+ $scope.realm = realm;
+ Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
+ $scope.realmManagementClientId = data[0].id;
+ });
+ GroupManagementPermissions.get({realm: realm.realm, group: group.id}, function(data) {
+ $scope.permissions = data;
+ });
+ $scope.setEnabled = function() {
+ var param = { enabled: $scope.permissions.enabled};
+ $scope.permissions = GroupManagementPermissions.update({realm: realm.realm, group: group.id}, param);
+ };
+
+
+});
+
+
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js
index 92219bb..f56ca8f 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js
@@ -144,4 +144,50 @@ module.service('AuthzDialog', function($modal) {
}
return dialog;
-});
\ No newline at end of file
+});
+
+module.factory('RoleManagementPermissions', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/management/permissions', {
+ realm : '@realm',
+ role : '@role'
+ }, {
+ update: {
+ method: 'PUT'
+ }
+ });
+});
+
+module.factory('UsersManagementPermissions', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/users-management-permissions', {
+ realm : '@realm'
+ }, {
+ update: {
+ method: 'PUT'
+ }
+ });
+});
+
+module.factory('ClientManagementPermissions', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/clients/:client/management/permissions', {
+ realm : '@realm',
+ client : '@client'
+ }, {
+ update: {
+ method: 'PUT'
+ }
+ });
+});
+
+module.factory('GroupManagementPermissions', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/groups/:group/management/permissions', {
+ realm : '@realm',
+ group : '@group'
+ }, {
+ update: {
+ method: 'PUT'
+ }
+ });
+});
+
+
+
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/services.js b/themes/src/main/resources/theme/base/admin/resources/js/services.js
index 50b50ab..e850b3b 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -842,28 +842,6 @@ 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) {
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role', {
realm : '@realm',
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-permissions.html
new file mode 100644
index 0000000..50241b2
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-permissions.html
@@ -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}}/clients">{{:: 'clients' | translate}}</a></li>
+ <li>{{client.clientId}}</li>
+ </ol>
+
+ <kc-tabs-client></kc-tabs-client>
+
+ <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}}-authz-client-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>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html
index d2d6c14..988c1fa 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html
@@ -2,7 +2,6 @@
<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>
@@ -30,7 +29,7 @@
<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 translate="{{scopeName}}-authz-role-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>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/group-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/group-permissions.html
new file mode 100644
index 0000000..61770c9
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/group-permissions.html
@@ -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}}/groups">{{:: 'groups' | translate}}</a></li>
+ <li>{{group.name}}</li>
+ </ol>
+
+ <kc-tabs-group></kc-tabs-group>
+
+ <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/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
+ <td translate="{{scopeName}}-authz-group-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>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html
index 82c8413..9c03333 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html
@@ -28,7 +28,7 @@
<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 translate="{{scopeName}}-authz-role-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>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/users-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/users-permissions.html
index 92a9067..4a5661f 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/users-permissions.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/users-permissions.html
@@ -24,7 +24,7 @@
<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 translate="{{scopeName}}-authz-users-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>
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
index 2a3be32..a18c31f 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
@@ -43,5 +43,9 @@
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/service-account-roles">{{:: 'service-account-roles' | translate}}</a>
<kc-tooltip>{{:: 'service-account-roles.tooltip' | translate}}</kc-tooltip>
</li>
+ <li ng-class="{active: path[4] == 'permissions'}">
+ <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
+ <kc-tooltip>{{:: 'manage-permissions-client.tooltip' | translate}}</kc-tooltip>
+ </li>
</ul>
</div>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-group.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-group.html
index c242336..3aa12bc 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-group.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-group.html
@@ -9,5 +9,9 @@
<li ng-class="{active: path[4] == 'attributes'}"><a href="#/realms/{{realm.realm}}/groups/{{group.id}}/attributes">{{:: 'attributes' | translate}}</a></li>
<li ng-class="{active: path[4] == 'role-mappings'}" ><a href="#/realms/{{realm.realm}}/groups/{{group.id}}/role-mappings">{{:: 'role-mappings' | translate}}</a></li>
<li ng-class="{active: path[4] == 'members'}"><a href="#/realms/{{realm.realm}}/groups/{{group.id}}/members">{{:: 'members' | translate}}</a></li>
+ <li ng-class="{active: path[4] == 'permissions'}">
+ <a href="#/realms/{{realm.realm}}/groups/{{group.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
+ <kc-tooltip>{{:: 'manage-permissions-group.tooltip' | translate}}</kc-tooltip>
+ </li>
</ul>
</div>
\ No newline at end of file