Improve Permission Management (#2604)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-08-12 14:09:27 +03:00
committed by GitHub
parent 5b299e0a62
commit 441b78460d
40 changed files with 361 additions and 351 deletions

View File

@@ -36,25 +36,38 @@ import org.springframework.util.function.SingletonSupplier;
@Slf4j
public final class SpPermission {
public static final String CREATE_TARGET = "CREATE_TARGET";
public static final String READ_TARGET = "READ_TARGET";
public static final String UPDATE_TARGET = "UPDATE_TARGET";
public static final String DELETE_TARGET = "DELETE_TARGET";
// Permission prefixes
public static final String CREATE_PREFIX = "CREATE_";
public static final String READ_PREFIX = "READ_";
public static final String UPDATE_PREFIX = "UPDATE_";
public static final String DELETE_PREFIX = "DELETE_";
// Permission groups
public static final String TARGET = "TARGET";
public static final String TARGET_TYPE = "TARGET_TYPE";
public static final String SOFTWARE_MODULE = "SOFTWARE_MODULE";
public static final String DISTRIBUTION_SET = "DISTRIBUTION_SET";
public static final String ROLLOUT = "ROLLOUT";
public static final String TENANT_CONFIGURATION = "TENANT_CONFIGURATION";
public static final String CREATE_TARGET = CREATE_PREFIX + TARGET;
public static final String READ_TARGET = READ_PREFIX + TARGET;
public static final String UPDATE_TARGET = UPDATE_PREFIX + TARGET;
public static final String DELETE_TARGET = DELETE_PREFIX + TARGET;
/**
* Permission to read the target security token. The security token is security
* concerned and should be protected. So the combination
* {@linkplain #READ_TARGET} and {@code READ_TARGET_SEC_TOKEN} is necessary to
* be able to read the security token of a target.
*/
public static final String READ_TARGET_SEC_TOKEN = "READ_TARGET_SECURITY_TOKEN";
public static final String READ_TARGET_SEC_TOKEN = READ_TARGET + "_SECURITY_TOKEN";
public static final String CREATE_TARGET_TYPE = "CREATE_TARGET_TYPE";
public static final String READ_TARGET_TYPE = "READ_TARGET_TYPE";
public static final String UPDATE_TARGET_TYPE = "UPDATE_TARGET_TYPE";
public static final String DELETE_TARGET_TYPE = "DELETE_TARGET_TYPE";
public static final String READ_TARGET_TYPE = READ_PREFIX + TARGET_TYPE;
public static final String UPDATE_TARGET_TYPE = UPDATE_PREFIX + TARGET_TYPE;
public static final String DELETE_TARGET_TYPE = DELETE_PREFIX + TARGET_TYPE;
public static final String READ_DISTRIBUTION_SET = "READ_DISTRIBUTION_SET";
public static final String UPDATE_DISTRIBUTION_SET = "UPDATE_DISTRIBUTION_SET";
public static final String READ_DISTRIBUTION_SET = READ_PREFIX + DISTRIBUTION_SET;
public static final String UPDATE_DISTRIBUTION_SET = UPDATE_PREFIX + DISTRIBUTION_SET;
public static final String READ_REPOSITORY = "READ_REPOSITORY";
public static final String UPDATE_REPOSITORY = "UPDATE_REPOSITORY";
@@ -66,7 +79,8 @@ public final class SpPermission {
/**
* Permission to read the tenant settings.
*/
public static final String READ_TENANT_CONFIGURATION = "READ_TENANT_CONFIGURATION";
public static final String READ_TENANT_CONFIGURATION = READ_PREFIX + TENANT_CONFIGURATION;
/**
* Permission to read the gateway security token. The gateway security token is security
* concerned and should be protected. So in addition to {@linkplain #READ_TENANT_CONFIGURATION},
@@ -74,19 +88,15 @@ public final class SpPermission {
* implies both permissions - so it is sufficient to read the gateway security token.
*/
public static final String READ_GATEWAY_SEC_TOKEN = "READ_GATEWAY_SECURITY_TOKEN";
/**
* Permission to administrate the tenant settings.
*/
public static final String TENANT_CONFIGURATION = "TENANT_CONFIGURATION";
public static final String CREATE_ROLLOUT = "CREATE_ROLLOUT";
public static final String READ_ROLLOUT = "READ_ROLLOUT";
public static final String UPDATE_ROLLOUT = "UPDATE_ROLLOUT";
public static final String DELETE_ROLLOUT = "DELETE_ROLLOUT";
public static final String CREATE_ROLLOUT = CREATE_PREFIX + ROLLOUT;
public static final String READ_ROLLOUT = READ_PREFIX + ROLLOUT;
public static final String UPDATE_ROLLOUT = UPDATE_PREFIX + ROLLOUT;
public static final String DELETE_ROLLOUT = DELETE_PREFIX + ROLLOUT;
/** Permission to approve or deny a rollout prior to starting. */
public static final String APPROVE_ROLLOUT = "APPROVE_ROLLOUT";
public static final String APPROVE_ROLLOUT = "APPROVE_" + ROLLOUT;
/** Permission to start/stop/resume a rollout. */
public static final String HANDLE_ROLLOUT = "HANDLE_ROLLOUT";
public static final String HANDLE_ROLLOUT = "HANDLE_" + ROLLOUT;
/** Permission to administrate the system on a global, i.e. tenant independent scale. That includes the deletion of tenants. */
public static final String SYSTEM_ADMIN = "SYSTEM_ADMIN";
@@ -108,7 +118,10 @@ public final class SpPermission {
DELETE_REPOSITORY > DELETE_SOFTWARE_MODULE
""";
public static final String TENANT_CONFIGURATION_HIERARCHY = """
TENANT_CONFIGURATION > CREATE_TENANT_CONFIGURATION
TENANT_CONFIGURATION > READ_TENANT_CONFIGURATION
TENANT_CONFIGURATION > UPDATE_TENANT_CONFIGURATION
TENANT_CONFIGURATION > DELETE_TENANT_CONFIGURATION
TENANT_CONFIGURATION > READ_GATEWAY_SECURITY_TOKEN
""";

View File

@@ -25,10 +25,12 @@ public final class SpRole {
public static final String ROLLOUT_ADMIN = "ROLE_ROLLOUT_ADMIN";
public static final String TENANT_ADMIN = "ROLE_TENANT_ADMIN";
/**
* The role which contains the spring security context in case the system is executing code which is necessary to be privileged.
*/
/** The role which contains the spring security context in case the system is executing code which is necessary to be privileged. */
public static final String SYSTEM_ROLE = "ROLE_SYSTEM_CODE";
/** The role which contains in the spring security context in case a controller is authenticated */
public static final String CONTROLLER_ROLE = "ROLE_CONTROLLER";
/** The role which contained in the spring security context in case that a controller is authenticated, but only as 'anonymous'. */
public static final String CONTROLLER_ROLE_ANONYMOUS = "ROLE_CONTROLLER_ANONYMOUS";
private static final String IMPLIES = " > ";
private static final String LINE_BREAK = "\n";

View File

@@ -36,35 +36,8 @@ import org.springframework.security.access.prepost.PreAuthorize;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class SpringEvalExpressions {
public static final String BRACKET_OPEN = "(";
public static final String BRACKET_CLOSE = ")";
public static final String HAS_AUTH_PREFIX = "hasAuthority" + BRACKET_OPEN + "'";
public static final String HAS_AUTH_SUFFIX = "'" + BRACKET_CLOSE;
public static final String HAS_AUTH_AND = " and ";
public static final String HAS_AUTH_OR = " or ";
/**
* The role which contains in the spring security context in case ancontroller is authenticated.
*/
public static final String CONTROLLER_ROLE = "ROLE_CONTROLLER";
/**
* The role which contained in the spring security context in case that a controller is authenticated, but only as 'anonymous'.
*/
public static final String CONTROLLER_ROLE_ANONYMOUS = "ROLE_CONTROLLER_ANONYMOUS";
public static final String IS_SYSTEM_CODE = HAS_AUTH_PREFIX + SpRole.SYSTEM_ROLE + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_SYSTEM_ADMIN = HAS_AUTH_PREFIX + SpPermission.SYSTEM_ADMIN + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_CREATE_TARGET = HAS_AUTH_PREFIX + SpPermission.CREATE_TARGET + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_UPDATE_TARGET = HAS_AUTH_PREFIX + SpPermission.UPDATE_TARGET + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_READ_TARGET = HAS_AUTH_PREFIX + SpPermission.READ_TARGET + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_DELETE_TARGET = HAS_AUTH_PREFIX + SpPermission.DELETE_TARGET + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_CREATE_TARGET_TYPE = HAS_AUTH_PREFIX + SpPermission.CREATE_TARGET_TYPE + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_UPDATE_TARGET_TYPE = HAS_AUTH_PREFIX + SpPermission.UPDATE_TARGET_TYPE + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_READ_TARGET_TYPE = HAS_AUTH_PREFIX + SpPermission.READ_TARGET_TYPE + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_DELETE_TARGET_TYPE = HAS_AUTH_PREFIX + SpPermission.DELETE_TARGET_TYPE + HAS_AUTH_SUFFIX;
public static final String IS_SYSTEM_CODE = "hasAuthority('ROLE_SYSTEM_CODE')";
public static final String HAS_AUTH_SYSTEM_ADMIN = "hasAuthority('SYSTEM_ADMIN')";
// evaluated to <permission>_<permissionGroup> (e.g. DISTRIBUTION_SET_CREATE)
public static final String HAS_CREATE_REPOSITORY = "hasPermission(#root, 'CREATE')";
@@ -72,25 +45,5 @@ public final class SpringEvalExpressions {
public static final String HAS_UPDATE_REPOSITORY = "hasPermission(#root, 'UPDATE')";
public static final String HAS_DELETE_REPOSITORY = "hasPermission(#root, 'DELETE')";
public static final String HAS_AUTH_DOWNLOAD_ARTIFACT = HAS_AUTH_PREFIX + SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX
+ SpPermission.READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + SpPermission.UPDATE_TARGET + HAS_AUTH_SUFFIX
+ BRACKET_CLOSE;
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE = HAS_AUTH_PREFIX + SpPermission.CREATE_ROLLOUT + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_READ = HAS_AUTH_PREFIX + SpPermission.READ_ROLLOUT + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE = HAS_AUTH_PREFIX + SpPermission.UPDATE_ROLLOUT + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_DELETE = HAS_AUTH_PREFIX + SpPermission.DELETE_ROLLOUT + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_APPROVE = HAS_AUTH_PREFIX + SpPermission.APPROVE_ROLLOUT + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_HANDLE = HAS_AUTH_PREFIX + SpPermission.HANDLE_ROLLOUT + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ = BRACKET_OPEN + HAS_AUTH_PREFIX
+ SpPermission.READ_ROLLOUT + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + SpPermission.READ_TARGET + HAS_AUTH_SUFFIX
+ BRACKET_CLOSE;
public static final String HAS_AUTH_TENANT_CONFIGURATION_READ = HAS_AUTH_PREFIX + SpPermission.READ_TENANT_CONFIGURATION + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_TENANT_CONFIGURATION = HAS_AUTH_PREFIX + SpPermission.TENANT_CONFIGURATION + HAS_AUTH_SUFFIX;
public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" + CONTROLLER_ROLE + "')";
public static final String IS_CONTROLLER_OR_HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET = IS_CONTROLLER + HAS_AUTH_OR + HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET;
public static final String IS_CONTROLLER = "hasAnyRole('" + SpRole.CONTROLLER_ROLE_ANONYMOUS + "', '" + SpRole.CONTROLLER_ROLE + "')";
}

View File

@@ -24,7 +24,6 @@ import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.im.authentication.SpRole;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
@@ -107,7 +106,7 @@ public class SystemSecurityContext {
*/
public <T> T runAsControllerAsTenant(@NotEmpty final String tenant, @NotNull final Callable<T> callable) {
final SecurityContext oldContext = SecurityContextHolder.getContext();
final List<SimpleGrantedAuthority> authorities = List.of(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS));
final List<SimpleGrantedAuthority> authorities = List.of(new SimpleGrantedAuthority(SpRole.CONTROLLER_ROLE_ANONYMOUS));
try {
return tenantAware.runAsTenant(tenant, () -> {
setCustomSecurityContext(tenant, oldContext.getAuthentication().getPrincipal(), authorities);