Fine grained admin permissions feature V2
Closes #34563 Signed-off-by: vramik <vramik@redhat.com>
This commit is contained in:
parent
33cae33ae4
commit
b1ff9511d1
10 changed files with 42 additions and 23 deletions
2
.github/workflows/js-ci.yml
vendored
2
.github/workflows/js-ci.yml
vendored
|
@ -240,7 +240,7 @@ jobs:
|
|||
- name: Start Keycloak server
|
||||
run: |
|
||||
tar xfvz keycloak-999.0.0-SNAPSHOT.tar.gz
|
||||
keycloak-999.0.0-SNAPSHOT/bin/kc.sh start-dev --features=admin-fine-grained-authz,transient-users &> ~/server.log &
|
||||
keycloak-999.0.0-SNAPSHOT/bin/kc.sh start-dev --features=admin-fine-grained-authz:v1,transient-users &> ~/server.log &
|
||||
env:
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
|
||||
|
|
|
@ -53,7 +53,9 @@ public class Profile {
|
|||
|
||||
ACCOUNT_V3("Account Console version 3", Type.DEFAULT, 3, Feature.ACCOUNT_API),
|
||||
|
||||
ADMIN_FINE_GRAINED_AUTHZ("Fine-Grained Admin Permissions", Type.PREVIEW),
|
||||
ADMIN_FINE_GRAINED_AUTHZ("Fine-Grained Admin Permissions", Type.PREVIEW, 1),
|
||||
|
||||
ADMIN_FINE_GRAINED_AUTHZ_V2("Fine-Grained Admin Permissions version 2", Type.EXPERIMENTAL, 2, Feature.AUTHORIZATION),
|
||||
|
||||
ADMIN_API("Admin API", Type.DEFAULT),
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public class ProfileTest {
|
|||
|
||||
private static final Profile.Feature DEFAULT_FEATURE = Profile.Feature.AUTHORIZATION;
|
||||
private static final Profile.Feature DISABLED_BY_DEFAULT_FEATURE = Profile.Feature.DOCKER;
|
||||
private static final Profile.Feature PREVIEW_FEATURE = Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ;
|
||||
private static final Profile.Feature PREVIEW_FEATURE = Profile.Feature.TOKEN_EXCHANGE;
|
||||
private static final Profile.Feature EXPERIMENTAL_FEATURE = Profile.Feature.DYNAMIC_SCOPES;
|
||||
private static Profile.Feature DEPRECATED_FEATURE = Profile.Feature.LOGIN_V1;
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ public class FeaturesDistTest {
|
|||
|
||||
@Test
|
||||
@EnabledOnOs(value = { OS.LINUX, OS.MAC }, disabledReason = "different shell escaping behaviour on Windows.")
|
||||
@Launch({StartDev.NAME, "--features=token-exchange,admin-fine-grained-authz"})
|
||||
@Launch({StartDev.NAME, "--features=token-exchange,admin-fine-grained-authz:v1"})
|
||||
public void testEnableMultipleFeatures(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertStartedDevMode();
|
||||
|
@ -100,7 +100,7 @@ public class FeaturesDistTest {
|
|||
|
||||
@Test
|
||||
@EnabledOnOs(value = { OS.WINDOWS }, disabledReason = "different shell escaping behaviour on Windows.")
|
||||
@Launch({StartDev.NAME, "--features=\"token-exchange,admin-fine-grained-authz\""})
|
||||
@Launch({StartDev.NAME, "--features=\"token-exchange,admin-fine-grained-authz:v1\""})
|
||||
public void testWinEnableMultipleFeatures(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertStartedDevMode();
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.eclipse.microprofile.openapi.annotations.Operation;
|
|||
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.reactive.NoCache;
|
||||
|
@ -90,6 +89,7 @@ import jakarta.ws.rs.Produces;
|
|||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -702,6 +702,7 @@ public class ClientResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.CLIENTS)
|
||||
@Operation( summary = "Return object stating whether client Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference getManagementPermissions() {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
auth.roles().requireView(client);
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
|
@ -711,7 +712,7 @@ public class ClientResource {
|
|||
return toMgmtRef(client, permissions);
|
||||
}
|
||||
|
||||
public static ManagementPermissionReference toMgmtRef(ClientModel client, AdminPermissionManagement permissions) {
|
||||
private ManagementPermissionReference toMgmtRef(ClientModel client, AdminPermissionManagement permissions) {
|
||||
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||
ref.setEnabled(true);
|
||||
ref.setResource(permissions.clients().resource(client).getId());
|
||||
|
@ -734,6 +735,7 @@ public class ClientResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.CLIENTS)
|
||||
@Operation( summary = "Return object stating whether client Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
auth.clients().requireManage(client);
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
permissions.clients().setPermissionsEnabled(client, ref.isEnabled());
|
||||
|
|
|
@ -16,13 +16,12 @@
|
|||
*/
|
||||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.jboss.resteasy.reactive.NoCache;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.util.ObjectUtil;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
|
@ -42,10 +41,14 @@ import org.keycloak.services.resources.KeycloakOpenAPI;
|
|||
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.utils.GroupUtils;
|
||||
import org.keycloak.utils.ProfileHelper;
|
||||
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
|
@ -60,7 +63,6 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.keycloak.utils.GroupUtils;
|
||||
|
||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||
|
||||
|
@ -318,6 +320,7 @@ public class GroupResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.GROUPS)
|
||||
@Operation( summary = "Return object stating whether client Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference getManagementPermissions() {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
auth.groups().requireView(group);
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
|
@ -327,7 +330,7 @@ public class GroupResource {
|
|||
return toMgmtRef(group, permissions);
|
||||
}
|
||||
|
||||
public static ManagementPermissionReference toMgmtRef(GroupModel group, AdminPermissionManagement permissions) {
|
||||
private ManagementPermissionReference toMgmtRef(GroupModel group, AdminPermissionManagement permissions) {
|
||||
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||
ref.setEnabled(true);
|
||||
ref.setResource(permissions.groups().resource(group).getId());
|
||||
|
@ -350,6 +353,7 @@ public class GroupResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.GROUPS)
|
||||
@Operation( summary = "Return object stating whether client Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
auth.groups().requireManage(group);
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
|
|
|
@ -24,11 +24,11 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
|||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.reactive.NoCache;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import org.keycloak.broker.provider.IdentityProvider;
|
||||
import org.keycloak.broker.provider.IdentityProviderFactory;
|
||||
import org.keycloak.broker.provider.IdentityProviderMapper;
|
||||
import org.keycloak.broker.social.SocialIdentityProvider;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
|
@ -53,10 +53,12 @@ import org.keycloak.services.resources.KeycloakOpenAPI;
|
|||
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.utils.ProfileHelper;
|
||||
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
|
@ -69,7 +71,6 @@ import jakarta.ws.rs.core.Response;
|
|||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -440,6 +441,7 @@ public class IdentityProviderResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.IDENTITY_PROVIDERS)
|
||||
@Operation( summary = "Return object stating whether client Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference getManagementPermissions() {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
this.auth.realm().requireViewIdentityProviders();
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
|
@ -449,7 +451,7 @@ public class IdentityProviderResource {
|
|||
return toMgmtRef(identityProviderModel, permissions);
|
||||
}
|
||||
|
||||
public static ManagementPermissionReference toMgmtRef(IdentityProviderModel model, AdminPermissionManagement permissions) {
|
||||
private ManagementPermissionReference toMgmtRef(IdentityProviderModel model, AdminPermissionManagement permissions) {
|
||||
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||
ref.setEnabled(true);
|
||||
ref.setResource(permissions.idps().resource(model).getId());
|
||||
|
@ -472,6 +474,7 @@ public class IdentityProviderResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.IDENTITY_PROVIDERS)
|
||||
@Operation( summary = "Return object stating whether client Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
this.auth.realm().requireManageIdentityProviders();
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
permissions.idps().setPermissionsEnabled(identityProviderModel, ref.isEnabled());
|
||||
|
|
|
@ -30,12 +30,9 @@ import java.util.Map;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.FormParam;
|
||||
import jakarta.ws.rs.GET;
|
||||
|
@ -54,6 +51,9 @@ import jakarta.ws.rs.core.StreamingOutput;
|
|||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.reactive.NoCache;
|
||||
|
@ -515,6 +515,7 @@ public class RealmAdminResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
|
||||
@Operation()
|
||||
public ManagementPermissionReference getUserMgmtPermissions() {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
|
@ -534,6 +535,7 @@ public class RealmAdminResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
|
||||
@Operation()
|
||||
public ManagementPermissionReference setUsersManagementPermissionsEnabled(ManagementPermissionReference ref) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
|
||||
|
@ -545,8 +547,7 @@ public class RealmAdminResource {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static ManagementPermissionReference toUsersMgmtRef(AdminPermissionManagement permissions) {
|
||||
private ManagementPermissionReference toUsersMgmtRef(AdminPermissionManagement permissions) {
|
||||
ManagementPermissionReference ref = new ManagementPermissionReference();
|
||||
ref.setEnabled(true);
|
||||
ref.setResource(permissions.users().resource().getId());
|
||||
|
|
|
@ -23,7 +23,7 @@ import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
|||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.reactive.NoCache;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
|
@ -34,15 +34,16 @@ import org.keycloak.models.utils.ModelToRepresentation;
|
|||
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.resources.KeycloakOpenAPI;
|
||||
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.utils.ProfileHelper;
|
||||
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
|
@ -285,6 +286,7 @@ public class RoleByIdResource extends RoleResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.ROLES_BY_ID)
|
||||
@Operation( summary = "Return object stating whether role Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference getManagementPermissions(final @PathParam("role-id") String id) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireView(role);
|
||||
|
||||
|
@ -318,6 +320,7 @@ public class RoleByIdResource extends RoleResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.ROLES_BY_ID)
|
||||
@Operation( summary = "Return object stating whether role Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-id") String id, ManagementPermissionReference ref) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
RoleModel role = getRoleModel(id);
|
||||
auth.roles().requireManage(role);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
|||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.jboss.resteasy.reactive.NoCache;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.util.Encode;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
|
@ -45,12 +45,14 @@ import org.keycloak.services.resources.KeycloakOpenAPI;
|
|||
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.utils.ProfileHelper;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
|
@ -428,6 +430,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.ROLES)
|
||||
@Operation( summary = "Return object stating whether role Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference getManagementPermissions(final @PathParam("role-name") String roleName) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
auth.roles().requireView(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
|
@ -456,6 +459,7 @@ public class RoleContainerResource extends RoleResource {
|
|||
@Tag(name = KeycloakOpenAPI.Admin.Tags.ROLES)
|
||||
@Operation( summary = "Return object stating whether role Authorization permissions have been initialized or not and a reference")
|
||||
public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-name") String roleName, ManagementPermissionReference ref) {
|
||||
ProfileHelper.requireFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ);
|
||||
auth.roles().requireManage(roleContainer);
|
||||
RoleModel role = roleContainer.getRole(roleName);
|
||||
if (role == null) {
|
||||
|
|
Loading…
Reference in a new issue