Finalize and polish fine-grained permission (#2660)

* Remove _REPOSITORY_ permissions -> replaced with _SOFTWARE_MODULE_, _SOFTWARE_MODULE_TYPE_, _DISTRIBUTION_SET_, _DISTRIBUTION_SET_TYPE_ permissions
* Still kept _ROLE_REPOSITORY_ADMIN_ role granting all repository fine-graned permissions
* Added dedicated _TARGET_TYPE_ permission set - the _TARGET_ permissions just grant _READ_TARGET_TYPE_ (analogically _SOFTWARE_MODULE_ permissions grant _READ_SOFTWARE_MODULE_TYPE_ and _DISTRIBUTION_SET_ grants _READ_DISTRIBUTON_SET_TYPE_
* Hierarcy is not configurable - could be completely replaced by setting spring application property org.eclipse.hawkbit.hierarchy or could be extended by adding rules using org.eclipse.hawkbit.hierarchy.ext

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-09-09 15:42:11 +03:00
committed by GitHub
parent f2e6344775
commit ae3a004da0
16 changed files with 182 additions and 219 deletions

View File

@@ -17,7 +17,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import jakarta.validation.ValidationException;
@@ -88,7 +88,6 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
private final DeploymentManagement deployManagement;
private final SystemManagement systemManagement;
private final MgmtDistributionSetMapper mgmtDistributionSetMapper;
private final SystemSecurityContext systemSecurityContext;
private final TenantConfigHelper tenantConfigHelper;
@SuppressWarnings("java:S107")
@@ -112,7 +111,6 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
this.mgmtDistributionSetMapper = mgmtDistributionSetMapper;
this.systemManagement = systemManagement;
this.systemSecurityContext = systemSecurityContext;
}
@Override
@@ -144,23 +142,27 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
public ResponseEntity<List<MgmtDistributionSet>> createDistributionSets(final List<MgmtDistributionSetRequestBodyPost> sets) {
log.debug("creating {} distribution sets", sets.size());
// set default Ds type if ds type is null
final String defaultDsKey = systemSecurityContext.runAsSystem(systemManagement.getTenantMetadata().getDefaultDsType()::getKey);
final String defaultDsKey = systemManagement.getTenantMetadata().getDefaultDsType().getKey();
sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(defaultDsKey));
//check if there is already deleted DS Type
for (final MgmtDistributionSetRequestBodyPost ds : sets) {
final Optional<? extends DistributionSetType> opt = distributionSetTypeManagement.findByKey(ds.getType());
opt.ifPresent(dsType -> {
if (dsType.isDeleted()) {
final String text = "Cannot create Distribution Set from type with key {0}. Distribution Set Type already deleted!";
final String message = MessageFormat.format(text, dsType.getKey());
throw new ValidationException(message);
}
});
}
// check if target ds types exist and are not deleted, also caches them
final Map<String, DistributionSetType> dsTypeKeyToDsType = sets.stream()
.map(MgmtDistributionSetRequestBodyPost::getType)
.distinct()
.collect(Collectors.toMap(
Function.identity(),
dsTypeKey ->
distributionSetTypeManagement.findByKey(dsTypeKey).map(dsType -> {
if (dsType.isDeleted()) {
throw new ValidationException(MessageFormat.format(
"Cannot create Distribution Set from type with key {0}. Distribution Set Type already deleted!",
dsTypeKey));
}
return dsType;
}).orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, dsTypeKey))));
final Collection<? extends DistributionSet> createdDSets = distributionSetManagement
.create(mgmtDistributionSetMapper.fromRequest(sets));
final Collection<? extends DistributionSet> createdDSets =
distributionSetManagement.create(mgmtDistributionSetMapper.fromRequest(sets, defaultDsKey, dsTypeKeyToDsType));
log.debug("{} distribution sets created, return status {}", sets.size(), HttpStatus.CREATED);
return new ResponseEntity<>(MgmtDistributionSetMapper.toResponseDistributionSets(createdDSets), HttpStatus.CREATED);

View File

@@ -17,6 +17,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -63,8 +64,38 @@ public class MgmtDistributionSetMapper {
this.systemManagement = systemManagement;
}
public List<DistributionSetManagement.Create> fromRequest(final Collection<MgmtDistributionSetRequestBodyPost> sets) {
return sets.stream().map(this::fromRequest).toList();
public List<DistributionSetManagement.Create> fromRequest(
final Collection<MgmtDistributionSetRequestBodyPost> sets,
final String defaultDsKey, final Map<String, DistributionSetType> dsTypeKeyToDsType) {
return sets.stream().<DistributionSetManagement.Create>map(dsRest -> {
final Set<Long> modules = new HashSet<>();
if (dsRest.getOs() != null) {
modules.add(dsRest.getOs().getId());
}
if (dsRest.getApplication() != null) {
modules.add(dsRest.getApplication().getId());
}
if (dsRest.getRuntime() != null) {
modules.add(dsRest.getRuntime().getId());
}
if (dsRest.getModules() != null) {
dsRest.getModules().forEach(module -> modules.add(module.getId()));
}
// distribution set type, if null by the REST call shall be replaced with the default tenant DS type
final String dsTypeKey = Objects.requireNonNull(dsRest.getType(), "Distribution set type must not be null");
final DistributionSetType dsType = dsTypeKeyToDsType.get(dsTypeKey);
if (dsType == null) {
// type should never null, cache is prefilled with all types
throw new EntityNotFoundException(DistributionSetType.class, defaultDsKey);
}
return DistributionSetManagement.Create.builder()
.type(dsType)
.name(dsRest.getName()).version(dsRest.getVersion())
.description(dsRest.getDescription())
.modules(findSoftwareModuleWithExceptionIfNotFound(modules))
.requiredMigrationStep(dsRest.getRequiredMigrationStep())
.build();
}).toList();
}
public static MgmtDistributionSet toResponse(final DistributionSet distributionSet) {
@@ -170,36 +201,6 @@ public class MgmtDistributionSetMapper {
return sets.stream().map(MgmtDistributionSetMapper::toResponse).toList();
}
private DistributionSetManagement.Create fromRequest(final MgmtDistributionSetRequestBodyPost dsRest) {
final Set<Long> modules = new HashSet<>();
if (dsRest.getOs() != null) {
modules.add(dsRest.getOs().getId());
}
if (dsRest.getApplication() != null) {
modules.add(dsRest.getApplication().getId());
}
if (dsRest.getRuntime() != null) {
modules.add(dsRest.getRuntime().getId());
}
if (dsRest.getModules() != null) {
dsRest.getModules().forEach(module -> modules.add(module.getId()));
}
return DistributionSetManagement.Create.builder()
.type(Optional.ofNullable(dsRest.getType())
// if the type is supplied the type MUST exist
.map(typeKey -> distributionSetTypeManagement
.findByKey(typeKey)
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, typeKey)))
.map(DistributionSetType.class::cast)
// if here, the type is not supplied, use the default type
.orElseGet(() -> systemManagement.getTenantMetadata().getDefaultDsType()))
.name(dsRest.getName()).version(dsRest.getVersion())
.description(dsRest.getDescription())
.modules(findSoftwareModuleWithExceptionIfNotFound(modules))
.requiredMigrationStep(dsRest.getRequiredMigrationStep())
.build();
}
private Set<? extends SoftwareModule> findSoftwareModuleWithExceptionIfNotFound(final Set<Long> softwareModuleIds) {
if (CollectionUtils.isEmpty(softwareModuleIds)) {
return Collections.emptySet();

View File

@@ -73,7 +73,6 @@ class MgmtTargetTypeResourceTest extends AbstractManagementApiIntegrationTest {
principal = "targetTypeTester", allSpPermissions = true,
removeFromAllPermission = {
SpPermission.CREATE_TARGET, SpPermission.READ_TARGET, SpPermission.UPDATE_TARGET, SpPermission.DELETE_TARGET,
SpPermission.CREATE_REPOSITORY, SpPermission.READ_REPOSITORY, SpPermission.UPDATE_REPOSITORY, SpPermission.DELETE_REPOSITORY,
SpPermission.READ_TARGET_TYPE })
void getTargetTypesWithoutPermission() throws Exception {
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON))

View File

@@ -28,6 +28,16 @@ import org.springframework.http.HttpStatus;
*/
class PreAuthorizeEnabledTest extends AbstractSecurityTest {
/**
* Tests whether request succeed if a role is granted for the user
*/
@Test
@WithUser(authorities = { SpPermission.READ_DISTRIBUTION_SET }, autoCreateTenant = false)
void successIfHasRole() throws Exception {
mvc.perform(get("/rest/v1/distributionsets")).andExpect(result ->
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value()));
}
/**
* Tests whether request fail if a role is forbidden for the user
*/
@@ -38,23 +48,12 @@ class PreAuthorizeEnabledTest extends AbstractSecurityTest {
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.FORBIDDEN.value()));
}
/**
* Tests whether request succeed if a role is granted for the user
*/
@Test
@WithUser(authorities = { SpPermission.READ_REPOSITORY }, autoCreateTenant = false)
void successIfHasRole() throws Exception {
mvc.perform(get("/rest/v1/distributionsets")).andExpect(result ->
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value()));
}
/**
* Tests whether request returns distribution set if a role with scope is granted for the user
*/
@Test
@WithUser(authorities = {
SpPermission.CREATE_REPOSITORY,
SpPermission.READ_REPOSITORY,
"CREATE_DISTRIBUTION_SET", "READ_DISTRIBUTION_SET_TYPE",
SpPermission.READ_DISTRIBUTION_SET + "/name==DsOne" }, autoCreateTenant = false)
void successIfHasRoleWithScope() throws Exception {
createDsOne("successIfHasRoleWithScope");
@@ -69,8 +68,7 @@ class PreAuthorizeEnabledTest extends AbstractSecurityTest {
*/
@Test
@WithUser(authorities = {
SpPermission.CREATE_REPOSITORY,
SpPermission.READ_REPOSITORY,
"CREATE_DISTRIBUTION_SET", "READ_DISTRIBUTION_SET_TYPE",
SpPermission.READ_DISTRIBUTION_SET + "/name==DsOne2" }, autoCreateTenant = false)
void failIfHasNoForbiddingScope() throws Exception {
createDsOne("failIfHasNoForbiddingScope");
@@ -99,8 +97,7 @@ class PreAuthorizeEnabledTest extends AbstractSecurityTest {
mvc.perform(get("/rest/v1/system/configs")).andExpect(result -> {
// returns default DS type because of READ_TARGET
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value());
assertThat(new ObjectMapper().reader().readValue(result.getResponse().getContentAsString(), HashMap.class))
.hasSize(1);
assertThat(new ObjectMapper().reader().readValue(result.getResponse().getContentAsString(), HashMap.class)).hasSize(1);
});
}

View File

@@ -28,6 +28,16 @@ import org.springframework.http.HttpStatus;
*/
class PreAuthorizeEnabledTest extends AbstractSecurityTest {
/**
* Tests whether request succeed if a role is granted for the user
*/
@Test
@WithUser(authorities = { SpPermission.READ_DISTRIBUTION_SET }, autoCreateTenant = false)
void successIfHasRole() throws Exception {
mvc.perform(get("/rest/v1/distributionsets"))
.andExpect(result -> assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value()));
}
/**
* Tests whether request fail if a role is forbidden for the user
*/
@@ -38,23 +48,12 @@ class PreAuthorizeEnabledTest extends AbstractSecurityTest {
.andExpect(result -> assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.FORBIDDEN.value()));
}
/**
* Tests whether request succeed if a role is granted for the user
*/
@Test
@WithUser(authorities = { SpPermission.READ_REPOSITORY }, autoCreateTenant = false)
void successIfHasRole() throws Exception {
mvc.perform(get("/rest/v1/distributionsets"))
.andExpect(result -> assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value()));
}
/**
* Tests whether request returns distribution set if a role with scope is granted for the user
*/
@Test
@WithUser(authorities = {
SpPermission.CREATE_REPOSITORY,
SpPermission.READ_REPOSITORY,
"CREATE_DISTRIBUTION_SET", "READ_DISTRIBUTION_SET_TYPE",
SpPermission.READ_DISTRIBUTION_SET + "/name==DsOne" }, autoCreateTenant = false)
void successIfHasRoleWithScope() throws Exception {
createDsOne("successIfHasRoleWithScope");
@@ -69,8 +68,7 @@ class PreAuthorizeEnabledTest extends AbstractSecurityTest {
*/
@Test
@WithUser(authorities = {
SpPermission.CREATE_REPOSITORY,
SpPermission.READ_REPOSITORY,
"CREATE_DISTRIBUTION_SET", "READ_DISTRIBUTION_SET_TYPE",
SpPermission.READ_DISTRIBUTION_SET + "/name==DsOne2" }, autoCreateTenant = false)
void failIfHasNoForbiddingScope() throws Exception {
createDsOne("failIfHasNoForbiddingScope");
@@ -100,8 +98,7 @@ class PreAuthorizeEnabledTest extends AbstractSecurityTest {
.andExpect(result -> {
// returns default DS type because of READ_TARGET
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value());
assertThat(new ObjectMapper().reader().readValue(result.getResponse().getContentAsString(), HashMap.class))
.hasSize(1);
assertThat(new ObjectMapper().reader().readValue(result.getResponse().getContentAsString(), HashMap.class)).hasSize(1);
});
}

View File

@@ -62,7 +62,7 @@ public interface ArtifactManagement extends PermissionSupport {
* @param isEncrypted flag to indicate if artifact is encrypted.
* @return loaded {@link StoredArtifactInfo}
*/
@PreAuthorize("hasAuthority('" + SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT + "')" + " or " + SpringEvalExpressions.IS_CONTROLLER)
@PreAuthorize("hasAuthority('DOWNLOAD_REPOSITORY_ARTIFACT') or hasAuthority('" + SpPermission.SOFTWARE_MODULE_DOWNLOAD_ARTIFACT + "')" + " or " + SpringEvalExpressions.IS_CONTROLLER)
ArtifactStream getArtifactStream(@NotEmpty String sha1Hash, long softwareModuleId, final boolean isEncrypted);
/**

View File

@@ -74,7 +74,7 @@ public interface SystemManagement {
/**
* @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()}
*/
@PreAuthorize("hasAuthority('" + SpPermission.READ_REPOSITORY + "')" + " or "
@PreAuthorize("hasAuthority('" + SpPermission.READ_DISTRIBUTION_SET + "')" + " or "
+ "hasAuthority('READ_" + SpPermission.TARGET + "')" + " or "
+ "hasAuthority('READ_" + SpPermission.TENANT_CONFIGURATION + "')" + " or "
+ SpringEvalExpressions.IS_CONTROLLER)
@@ -83,7 +83,7 @@ public interface SystemManagement {
/**
* @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()} without details ({@link TenantMetaData#getDefaultDsType()})
*/
@PreAuthorize("hasAuthority('" + SpPermission.READ_REPOSITORY + "')" + " or "
@PreAuthorize("hasAuthority('" + SpPermission.READ_DISTRIBUTION_SET + "')" + " or "
+ "hasAuthority('READ_" + SpPermission.TARGET + "')" + " or "
+ "hasAuthority('READ_" + SpPermission.TENANT_CONFIGURATION + "')" + " or "
+ SpringEvalExpressions.IS_CONTROLLER)

View File

@@ -19,6 +19,7 @@ import org.aopalliance.intercept.MethodInvocation;
import org.eclipse.hawkbit.im.authentication.Hierarchy;
import org.eclipse.hawkbit.tenancy.configuration.ControllerPollProperties;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
@@ -38,6 +39,7 @@ import org.springframework.security.config.annotation.method.configuration.Enabl
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.util.ObjectUtils;
import org.springframework.util.function.SingletonSupplier;
/**
@@ -52,8 +54,16 @@ public class RepositoryConfiguration {
@Bean
@ConditionalOnMissingBean
static RoleHierarchy roleHierarchy() {
return RoleHierarchyImpl.fromHierarchy(Hierarchy.DEFAULT);
@SuppressWarnings("java:S3358") // java:S3358 better readable this way
RoleHierarchy roleHierarchy(
// if configured replaces the hierarchy completely
@Value("${org.eclipse.hawkbit.hierarchy:}") final String hierarchy,
// if the "hierarchy" property is empty, and this property is configured it is appended to the default hierarchy
@Value("${org.eclipse.hawkbit.hierarchy.ext:}") final String hierarchyExt) {
return RoleHierarchyImpl.fromHierarchy(
ObjectUtils.isEmpty(hierarchy)
? (ObjectUtils.isEmpty(hierarchyExt) ? Hierarchy.DEFAULT : Hierarchy.DEFAULT + hierarchyExt)
: hierarchy);
}
@Bean

View File

@@ -13,7 +13,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_DISTRIBUTION_SET;
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_REPOSITORY;
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_TARGET;
import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_DISTRIBUTION_SET;
import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_TARGET;
@@ -61,7 +60,6 @@ class DistributionSetAccessControllerTest extends AbstractJpaIntegrationTest {
final Action permittedAction = testdataFactory.performAssignment(permitted);
runAs(withUser("user",
READ_REPOSITORY,
READ_DISTRIBUTION_SET + "/id==" + permitted.getId(),
READ_TARGET +"/controllerId==" + permittedAction.getTarget().getControllerId()), () -> {
final Long permittedActionId = permitted.getId();
@@ -114,7 +112,6 @@ class DistributionSetAccessControllerTest extends AbstractJpaIntegrationTest {
final SoftwareModule swModule = testdataFactory.createSoftwareModuleOs();
runAs(withUser("user",
READ_REPOSITORY,
READ_DISTRIBUTION_SET + "/id==" + permitted.getId() + " or id==" + readOnly.getId(),
UPDATE_DISTRIBUTION_SET + "/id==" + permitted.getId()), () -> {
// verify distributionSetManagement#assignSoftwareModules
@@ -177,7 +174,6 @@ class DistributionSetAccessControllerTest extends AbstractJpaIntegrationTest {
distributionSetManagement.assignTag(Arrays.asList(permitted.getId(), readOnly.getId(), hidden.getId()), dsTagId);
runAs(withUser("user",
READ_REPOSITORY,
READ_DISTRIBUTION_SET + "/id==" + permitted.getId() + " or id==" + readOnly.getId(),
UPDATE_DISTRIBUTION_SET + "/id==" + permitted.getId()), () -> {
assertThat(distributionSetManagement.findByTag(dsTagId, Pageable.unpaged()).get().map(Identifiable::getId)
@@ -245,7 +241,6 @@ class DistributionSetAccessControllerTest extends AbstractJpaIntegrationTest {
.create(TargetFilterQueryManagement.Create.builder().name("test").query("id==*").build());
runAs(withUser("user",
READ_REPOSITORY,
READ_DISTRIBUTION_SET + "/id==" + permitted.getId() + " or id==" + readOnly.getId(),
UPDATE_DISTRIBUTION_SET + "/id==" + permitted.getId(),
// read / update target needed to update target filter query

View File

@@ -13,7 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.eclipse.hawkbit.im.authentication.SpPermission.CREATE_ROLLOUT;
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_REPOSITORY;
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_DISTRIBUTION_SET;
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_ROLLOUT;
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_TARGET;
import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_TARGET;
@@ -126,8 +126,7 @@ class TargetAccessControllerTest extends AbstractJpaIntegrationTest {
runAs(withUser("user",
READ_TARGET + "/controllerId==" + permittedTarget.getControllerId() + " or controllerId==" + readOnlyTargetControllerId,
UPDATE_TARGET + "/controllerId==" + permittedTarget.getControllerId(),
READ_REPOSITORY),
UPDATE_TARGET + "/controllerId==" + permittedTarget.getControllerId()),
() -> {
// verify targetManagement#findByTag
assertThat(
@@ -194,9 +193,9 @@ class TargetAccessControllerTest extends AbstractJpaIntegrationTest {
.getControllerId();
runAs(withUser("user",
READ_DISTRIBUTION_SET,
READ_TARGET + "/controllerId==" + permittedTarget.getControllerId(),
UPDATE_TARGET + "/controllerId==" + permittedTarget.getControllerId(),
READ_REPOSITORY), () -> {
UPDATE_TARGET + "/controllerId==" + permittedTarget.getControllerId()), () -> {
final Long dsId = ds.getId();
assertThat(assignDistributionSet(dsId, permittedTarget.getControllerId()).getAssigned()).isEqualTo(1);
// assigning of not allowed target behaves as not found
@@ -220,9 +219,9 @@ class TargetAccessControllerTest extends AbstractJpaIntegrationTest {
.create(Create.builder().controllerId("device02").updateStatus(TargetUpdateStatus.REGISTERED).build());
runAs(withUser("user",
READ_DISTRIBUTION_SET,
READ_TARGET + "/controllerId==" + manageableTarget.getControllerId() + " or controllerId==" + readOnlyTarget.getControllerId(),
UPDATE_TARGET + "/controllerId==" + manageableTarget.getControllerId(),
READ_REPOSITORY), () -> {
UPDATE_TARGET + "/controllerId==" + manageableTarget.getControllerId()), () -> {
final Long firstDsId = firstDs.getId();
// assignment is permitted for manageableTarget
assertThat(assignDistributionSet(firstDsId, manageableTarget.getControllerId()).getAssigned()).isEqualTo(1);
@@ -253,10 +252,10 @@ class TargetAccessControllerTest extends AbstractJpaIntegrationTest {
final List<Target> hiddenTargets = testdataFactory.createTargets("hidden1", "hidden2", "hidden3", "hidden4", "hidden5");
runAs(withUser("user",
READ_DISTRIBUTION_SET,
READ_TARGET + "/controllerId=in=(" + String.join(", ", List.of(updateTargetControllerIds)) + ")" +
" or controllerId=in=(" + String.join(", ", List.of(readTargetControllerIds)) + ")",
UPDATE_TARGET + "/controllerId=in=(" + String.join(", ", List.of(updateTargetControllerIds)) + ")",
READ_REPOSITORY,
CREATE_ROLLOUT, READ_ROLLOUT), () -> {
final Rollout rollout = testdataFactory.createRolloutByVariables(
"testRollout", "description", updateTargets.size(), "id==*", ds, "50", "5");
@@ -299,7 +298,7 @@ class TargetAccessControllerTest extends AbstractJpaIntegrationTest {
READ_TARGET + "/controllerId=in=(" + String.join(", ", List.of(updateTargetControllerIds)) + ")" +
" or controllerId=in=(" + String.join(", ", List.of(readTargetControllerIds)) + ")",
UPDATE_TARGET + "/controllerId=in=(" + String.join(", ", List.of(updateTargetControllerIds)) + ")",
READ_REPOSITORY + "/id==" + distributionSet.getId()), () -> {
READ_DISTRIBUTION_SET + "/id==" + distributionSet.getId()), () -> {
targetFilterQueryManagement.updateAutoAssignDS(
new AutoAssignDistributionSetUpdate(targetFilterQuery.getId()).ds(distributionSet.getId()));

View File

@@ -400,7 +400,8 @@ class ArtifactManagementTest extends AbstractJpaIntegrationTest {
*/
@Test
@WithUser(allSpPermissions = true, removeFromAllPermission = {
SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT, SpRole.CONTROLLER_ROLE, SpRole.CONTROLLER_ROLE_ANONYMOUS })
SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT, SpPermission.SOFTWARE_MODULE_DOWNLOAD_ARTIFACT,
SpRole.CONTROLLER_ROLE, SpRole.CONTROLLER_ROLE_ANONYMOUS })
void getArtifactBinaryWithoutDownloadArtifactThrowsPermissionDenied() {
assertThatExceptionOfType(InsufficientPermissionException.class)
.as("Should not have worked with missing permission.")

View File

@@ -16,7 +16,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
@@ -56,21 +55,20 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
final InvalidationTestData invalidationTestData = createInvalidationTestData("verifyInvalidateDistributionSetStopAutoAssignment");
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), ActionCancellationType.NONE);
Collections.singletonList(invalidationTestData.distributionSet().getId()), ActionCancellationType.NONE);
final DistributionSetInvalidationCount distributionSetInvalidationCount = countEntitiesForInvalidation(distributionSetInvalidation);
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 0, 0);
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
rolloutHandler.handleAll();
assertThat(targetFilterQueryManagement.find(invalidationTestData.getTargetFilterQuery().getId()).get()
assertThat(targetFilterQueryManagement.find(invalidationTestData.targetFilterQuery().getId()).orElseThrow()
.getAutoAssignDistributionSet()).isNull();
assertThat(rolloutRepository.findById(invalidationTestData.getRollout().getId()).get().getStatus())
assertThat(rolloutRepository.findById(invalidationTestData.rollout().getId()).orElseThrow().getStatus())
.isNotIn(RolloutStatus.STOPPING, RolloutStatus.FINISHED);
for (final Target target : invalidationTestData.getTargets()) {
for (final Target target : invalidationTestData.targets()) {
// if status is pending, the assignment has not been canceled
assertThat(targetRepository.findById(target.getId()).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.PENDING);
assertThat(targetRepository.findById(target.getId()).orElseThrow().getUpdateStatus()).isEqualTo(TargetUpdateStatus.PENDING);
assertThat(findActionsByTarget(target)).hasSize(1);
assertThat(findActionsByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
}
@@ -81,27 +79,25 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
*/
@Test
void verifyInvalidateDistributionSetDoesNotStopRollouts() {
final InvalidationTestData invalidationTestData = createInvalidationTestData(
"verifyInvalidateDistributionSetStopRollouts");
final InvalidationTestData invalidationTestData = createInvalidationTestData("verifyInvalidateDistributionSetStopRollouts");
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), ActionCancellationType.NONE);
Collections.singletonList(invalidationTestData.distributionSet().getId()), ActionCancellationType.NONE);
final DistributionSetInvalidationCount distributionSetInvalidationCount = countEntitiesForInvalidation(distributionSetInvalidation);
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 0, 0);
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
rolloutHandler.handleAll();
assertThat(targetFilterQueryManagement.find(invalidationTestData.getTargetFilterQuery().getId()).get()
assertThat(targetFilterQueryManagement.find(invalidationTestData.targetFilterQuery().getId()).orElseThrow()
.getAutoAssignDistributionSet()).isNull();
assertThat(rolloutRepository.findById(invalidationTestData.getRollout().getId()).get().getStatus())
assertThat(rolloutRepository.findById(invalidationTestData.rollout().getId()).orElseThrow().getStatus())
.isEqualTo(RolloutStatus.READY);
assertNoScheduledActionsExist(invalidationTestData.getRollout());
for (final Target target : invalidationTestData.getTargets()) {
assertNoScheduledActionsExist(invalidationTestData.rollout());
for (final Target target : invalidationTestData.targets()) {
// if status is pending, the assignment has not been canceled
assertThat(
targetRepository.findById(invalidationTestData.getTargets().get(0).getId()).get().getUpdateStatus())
assertThat(targetRepository.findById(invalidationTestData.targets().get(0).getId()).orElseThrow().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.PENDING);
assertThat(findActionsByTarget(target)).hasSize(1);
assertThat(findActionsByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
@@ -113,23 +109,22 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
*/
@Test
void verifyInvalidateDistributionSetStopAllAndForceCancel() {
final InvalidationTestData invalidationTestData = createInvalidationTestData(
"verifyInvalidateDistributionSetStopAllAndForceCancel");
final InvalidationTestData invalidationTestData = createInvalidationTestData("verifyInvalidateDistributionSetStopAllAndForceCancel");
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), ActionCancellationType.FORCE);
Collections.singletonList(invalidationTestData.distributionSet().getId()), ActionCancellationType.FORCE);
final DistributionSetInvalidationCount distributionSetInvalidationCount = countEntitiesForInvalidation(distributionSetInvalidation);
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 5, 1);
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
rolloutHandler.handleAll();
assertThat(targetFilterQueryManagement.find(invalidationTestData.getTargetFilterQuery().getId()).get()
assertThat(targetFilterQueryManagement.find(invalidationTestData.targetFilterQuery().getId()).orElseThrow()
.getAutoAssignDistributionSet()).isNull();
// rollout should be deleted when force invalidation
assertThat(rolloutRepository.findById(invalidationTestData.getRollout().getId())).isEmpty();
assertNoScheduledActionsExist(invalidationTestData.getRollout());
assertAllRolloutActionsAreCancelled(invalidationTestData.getRollout());
assertThat(rolloutRepository.findById(invalidationTestData.rollout().getId())).isEmpty();
assertNoScheduledActionsExist(invalidationTestData.rollout());
assertAllRolloutActionsAreCancelled(invalidationTestData.rollout());
}
/**
@@ -140,19 +135,18 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
final InvalidationTestData invalidationTestData = createInvalidationTestData("verifyInvalidateDistributionSetStopAll");
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), ActionCancellationType.SOFT);
Collections.singletonList(invalidationTestData.distributionSet().getId()), ActionCancellationType.SOFT);
final DistributionSetInvalidationCount distributionSetInvalidationCount = countEntitiesForInvalidation(distributionSetInvalidation);
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 5, 1);
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
assertThat(targetFilterQueryManagement.find(invalidationTestData.getTargetFilterQuery().getId()).get()
assertThat(targetFilterQueryManagement.find(invalidationTestData.targetFilterQuery().getId()).orElseThrow()
.getAutoAssignDistributionSet()).isNull();
assertThat(rolloutRepository.findById(invalidationTestData.getRollout().getId()).get().getStatus())
assertThat(rolloutRepository.findById(invalidationTestData.rollout().getId()).orElseThrow().getStatus())
.isIn(RolloutStatus.STOPPING, RolloutStatus.FINISHED);
for (final Target target : invalidationTestData.getTargets()) {
assertThat(targetRepository.findById(target.getId()).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.PENDING);
for (final Target target : invalidationTestData.targets()) {
assertThat(targetRepository.findById(target.getId()).orElseThrow().getUpdateStatus()).isEqualTo(TargetUpdateStatus.PENDING);
assertThat(findActionsByTarget(target)).hasSize(1);
assertThat(findActionsByTarget(target).get(0).getStatus()).isEqualTo(Status.CANCELING);
}
@@ -182,74 +176,63 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
void verifyInvalidateInvalidatedDistributionSetDontThrowsException() {
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
distributionSetInvalidationManagement.invalidateDistributionSet(
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
ActionCancellationType.SOFT));
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()), ActionCancellationType.SOFT));
}
/**
* Verify that a user that has authority READ_REPOSITORY and UPDATE_REPOSITORY is allowed to invalidate a distribution set
* Verify that a user that has authority READ_DISTRIBUTION_SET and UPDATE_DISTRIBUTION_SET is allowed to invalidate a distribution set
*/
@Test
@WithUser(authorities = { "READ_REPOSITORY", "UPDATE_REPOSITORY" })
@WithUser(authorities = { "READ_DISTRIBUTION_SET", "UPDATE_DISTRIBUTION_SET" })
void verifyInvalidateWithReadAndUpdateRepoAuthority() {
final InvalidationTestData invalidationTestData = systemSecurityContext
.runAsSystem(() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAuthority"));
distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation(
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), ActionCancellationType.NONE));
assertThat(
distributionSetRepository.findById(invalidationTestData.getDistributionSet().getId()).get().isValid())
.isFalse();
Collections.singletonList(invalidationTestData.distributionSet().getId()), ActionCancellationType.NONE));
assertThat(distributionSetRepository.findById(invalidationTestData.distributionSet().getId()).orElseThrow().isValid()).isFalse();
}
/**
* Verify that a user that has authority READ_REPOSITORY, UPDATE_REPOSITORY and UPDATE_TARGET is allowed to invalidate a distribution set only without canceling rollouts
* Verify that a user that has authority READ_DISTRIBUTION_SET, UPDATE_DISTRIBUTION_SET and UPDATE_TARGET is allowed to invalidate a distribution set only without canceling rollouts
*/
@Test
@WithUser(authorities = { "READ_REPOSITORY", "UPDATE_REPOSITORY", "UPDATE_TARGET" })
@WithUser(authorities = { "READ_DISTRIBUTION_SET", "UPDATE_DISTRIBUTION_SET", "UPDATE_TARGET" })
void verifyInvalidateWithReadAndUpdateRepoAndUpdateTargetAuthority() {
final InvalidationTestData invalidationTestData = systemSecurityContext.runAsSystem(
() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAndUpdateTargetAuthority"));
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
List.of(invalidationTestData.getDistributionSet().getId()), ActionCancellationType.SOFT);
List.of(invalidationTestData.distributionSet().getId()), ActionCancellationType.SOFT);
assertThatExceptionOfType(InsufficientPermissionException.class)
.as("Insufficient permission exception expected")
.isThrownBy(() -> distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation));
distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation(
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), ActionCancellationType.NONE));
assertThat(
distributionSetRepository.findById(invalidationTestData.getDistributionSet().getId()).get().isValid())
.isFalse();
Collections.singletonList(invalidationTestData.distributionSet().getId()), ActionCancellationType.NONE));
assertThat(distributionSetRepository.findById(invalidationTestData.distributionSet().getId()).orElseThrow().isValid()).isFalse();
}
/**
* Verify that a user that has authority READ_REPOSITORY, UPDATE_REPOSITORY, UPDATE_ROLLOUT and UPDATE_TARGET is allowed to invalidate a distribution
* Verify that a user that has authority READ_DISTRIBUTION_SET, UPDATE_DISTRIBUTION_SET, UPDATE_ROLLOUT and UPDATE_TARGET is allowed to invalidate a distribution
*/
@Test
@WithUser(authorities = { "READ_REPOSITORY", "UPDATE_REPOSITORY", "UPDATE_TARGET", "UPDATE_ROLLOUT" })
@WithUser(authorities = { "READ_DISTRIBUTION_SET", "UPDATE_DISTRIBUTION_SET", "UPDATE_TARGET", "UPDATE_ROLLOUT" })
void verifyInvalidateWithReadAndUpdateRepoAndUpdateTargetAndUpdateRolloutAuthority() {
final InvalidationTestData invalidationTestData = systemSecurityContext.runAsSystem(
() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAndUpdateTargetAuthority"));
distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation(
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), ActionCancellationType.SOFT));
assertThat(
distributionSetRepository.findById(invalidationTestData.getDistributionSet().getId()).get().isValid())
.isFalse();
List.of(invalidationTestData.distributionSet().getId()), ActionCancellationType.SOFT));
assertThat(distributionSetRepository.findById(invalidationTestData.distributionSet().getId()).orElseThrow().isValid()).isFalse();
}
private void assertNoScheduledActionsExist(final Rollout rollout) {
assertThat(
actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), Status.SCHEDULED).getTotalElements())
.isZero();
assertThat(actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), Status.SCHEDULED).getTotalElements()).isZero();
}
private void assertAllRolloutActionsAreCancelled(final Rollout rollout) {
assertThat(
actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), Status.CANCELED).getTotalElements())
.isZero();
assertThat(actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), Status.CANCELED).getTotalElements()).isZero();
}
private InvalidationTestData createInvalidationTestData(final String testName) {
@@ -276,8 +259,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
return actionRepository.findAll(ActionSpecifications.byTargetControllerId(target.getControllerId()));
}
private DistributionSetInvalidationCount countEntitiesForInvalidation(
final DistributionSetInvalidation distributionSetInvalidation) {
private DistributionSetInvalidationCount countEntitiesForInvalidation(final DistributionSetInvalidation distributionSetInvalidation) {
return systemSecurityContext.runAsSystem(() -> {
final Collection<Long> setIds = distributionSetInvalidation.getDistributionSetIds();
final long rolloutsCount = distributionSetInvalidation.getActionCancellationType() != ActionCancellationType.NONE ? countRolloutsForInvalidation(setIds) : 0;
@@ -317,22 +299,6 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
.sum();
}
@Data
private static class InvalidationTestData {
private final DistributionSet distributionSet;
private final List<Target> targets;
private final TargetFilterQuery targetFilterQuery;
private final Rollout rollout;
public InvalidationTestData(
final DistributionSet distributionSet, final List<Target> targets,
final TargetFilterQuery targetFilterQuery, final Rollout rollout) {
super();
this.distributionSet = distributionSet;
this.targets = targets;
this.targetFilterQuery = targetFilterQuery;
this.rollout = rollout;
}
}
}
private record InvalidationTestData(
DistributionSet distributionSet, List<Target> targets, TargetFilterQuery targetFilterQuery, Rollout rollout) {}
}

View File

@@ -1393,10 +1393,10 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final WithUser userWithoutHandleRollout = SecurityContextSwitch.withUser(
"user_without_handle_rollout",
SpPermission.READ_REPOSITORY, SpPermission.READ_TARGET, SpPermission.CREATE_ROLLOUT);
SpPermission.READ_DISTRIBUTION_SET, SpPermission.READ_TARGET, SpPermission.CREATE_ROLLOUT);
final WithUser userWithHandleRollout = SecurityContextSwitch.withUser(
"user_with_handle_rollout",
SpPermission.READ_REPOSITORY, SpPermission.READ_TARGET, SpPermission.CREATE_ROLLOUT, SpPermission.HANDLE_ROLLOUT);
SpPermission.READ_DISTRIBUTION_SET, SpPermission.READ_TARGET, SpPermission.CREATE_ROLLOUT, SpPermission.HANDLE_ROLLOUT);
final WithUser userWithSystemRole = SecurityContextSwitch.withUser(
"user_with_system_role",
SpRole.SYSTEM_ROLE);

View File

@@ -21,7 +21,6 @@ public class Hierarchy {
SpPermission.SOFTWARE_MODULE_HIERARCHY +
SpPermission.DISTRIBUTION_SET_HIERARCHY +
SpPermission.TENANT_CONFIGURATION_HIERARCHY +
SpRole.DEFAULT_ROLE_HIERARCHY +
SpPermission.REPOSITORY_HIERARCHY;
SpRole.DEFAULT_ROLE_HIERARCHY;
// @formatter:on
}

View File

@@ -67,11 +67,14 @@ public final class SpPermission {
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 CREATE_REPOSITORY = "CREATE_REPOSITORY";
public static final String READ_REPOSITORY = "READ_REPOSITORY";
public static final String UPDATE_REPOSITORY = "UPDATE_REPOSITORY";
public static final String DELETE_REPOSITORY = "DELETE_REPOSITORY";
/**
* Deprecated since 0.10.0, use {@link #SOFTWARE_MODULE_DOWNLOAD_ARTIFACT} instead
*
* @deprecated since 0.10.0, use {@link #SOFTWARE_MODULE_DOWNLOAD_ARTIFACT} instead
*/
@Deprecated(since = "0.10.0", forRemoval = true)
public static final String DOWNLOAD_REPOSITORY_ARTIFACT = "DOWNLOAD_REPOSITORY_ARTIFACT";
public static final String SOFTWARE_MODULE_DOWNLOAD_ARTIFACT = SOFTWARE_MODULE + "_DOWNLOAD_ARTIFACT";
/**
* Permission to read the tenant settings.
@@ -124,27 +127,6 @@ public final class SpPermission {
TENANT_CONFIGURATION + IMPLY_UPDATE + TENANT_CONFIGURATION + "\n" +
TENANT_CONFIGURATION + IMPLY_DELETE + TENANT_CONFIGURATION + "\n" +
TENANT_CONFIGURATION + " > " + READ_GATEWAY_SECURITY_TOKEN + "\n";
public static final String REPOSITORY_HIERARCHY =
CREATE_REPOSITORY + IMPLY_CREATE + TARGET_TYPE + "\n" +
READ_REPOSITORY + IMPLY_READ + TARGET_TYPE + "\n" +
UPDATE_REPOSITORY + IMPLY_UPDATE + TARGET_TYPE + "\n" +
DELETE_REPOSITORY + IMPLY_DELETE + TARGET_TYPE + "\n" +
CREATE_REPOSITORY + IMPLY_CREATE + SOFTWARE_MODULE + "\n" +
READ_REPOSITORY + IMPLY_READ + SOFTWARE_MODULE + "\n" +
UPDATE_REPOSITORY + IMPLY_UPDATE + SOFTWARE_MODULE + "\n" +
DELETE_REPOSITORY + IMPLY_DELETE + SOFTWARE_MODULE + "\n" +
CREATE_REPOSITORY + IMPLY_CREATE + SOFTWARE_MODULE_TYPE + "\n" +
READ_REPOSITORY + IMPLY_READ + SOFTWARE_MODULE_TYPE + "\n" +
UPDATE_REPOSITORY + IMPLY_UPDATE + SOFTWARE_MODULE_TYPE + "\n" +
DELETE_REPOSITORY + IMPLY_DELETE + SOFTWARE_MODULE_TYPE + "\n" +
CREATE_REPOSITORY + IMPLY_CREATE + DISTRIBUTION_SET + "\n" +
READ_REPOSITORY + IMPLY_READ + DISTRIBUTION_SET + "\n" +
UPDATE_REPOSITORY + IMPLY_UPDATE + DISTRIBUTION_SET + "\n" +
DELETE_REPOSITORY + IMPLY_DELETE + DISTRIBUTION_SET + "\n" +
CREATE_REPOSITORY + IMPLY_CREATE + DISTRIBUTION_SET_TYPE + "\n" +
READ_REPOSITORY + IMPLY_READ + DISTRIBUTION_SET_TYPE + "\n" +
UPDATE_REPOSITORY + IMPLY_UPDATE + DISTRIBUTION_SET_TYPE + "\n" +
DELETE_REPOSITORY + IMPLY_DELETE + DISTRIBUTION_SET_TYPE + "\n";
// @formatter:on
private static final SingletonSupplier<List<String>> ALL_AUTHORITIES = SingletonSupplier.of(() -> {
@@ -163,7 +145,7 @@ public final class SpPermission {
// special
allPermissions.add(READ_TARGET_SECURITY_TOKEN);
allPermissions.add(READ_GATEWAY_SECURITY_TOKEN);
allPermissions.add(DOWNLOAD_REPOSITORY_ARTIFACT);
allPermissions.add(SOFTWARE_MODULE_DOWNLOAD_ARTIFACT);
allPermissions.add(APPROVE_ROLLOUT);
allPermissions.add(HANDLE_ROLLOUT);
@@ -176,6 +158,9 @@ public final class SpPermission {
// system permission, (!) take care with
allPermissions.add(SYSTEM_ADMIN);
// add deprecated permissions
allPermissions.add(DOWNLOAD_REPOSITORY_ARTIFACT);
return Collections.unmodifiableList(allPermissions);
});

View File

@@ -46,6 +46,24 @@ public final class SpRole {
TARGET_ADMIN + IMPLIES + SpPermission.READ_TARGET_TYPE + LINE_BREAK +
TARGET_ADMIN + IMPLIES + SpPermission.UPDATE_TARGET_TYPE + LINE_BREAK +
TARGET_ADMIN + IMPLIES + SpPermission.DELETE_TARGET_TYPE + LINE_BREAK;
public static final String REPOSITORY_ADMIN_HIERARCHY =
REPOSITORY_ADMIN + IMPLIES + SpPermission.CREATE_PREFIX + SpPermission.SOFTWARE_MODULE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.READ_PREFIX + SpPermission.SOFTWARE_MODULE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.UPDATE_PREFIX + SpPermission.SOFTWARE_MODULE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.DELETE_PREFIX + SpPermission.SOFTWARE_MODULE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.SOFTWARE_MODULE_DOWNLOAD_ARTIFACT + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.CREATE_PREFIX + SpPermission.SOFTWARE_MODULE_TYPE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.READ_PREFIX + SpPermission.SOFTWARE_MODULE_TYPE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.UPDATE_PREFIX + SpPermission.SOFTWARE_MODULE_TYPE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.DELETE_PREFIX + SpPermission.SOFTWARE_MODULE_TYPE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.CREATE_PREFIX + SpPermission.DISTRIBUTION_SET + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.READ_PREFIX + SpPermission.DISTRIBUTION_SET + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.UPDATE_PREFIX + SpPermission.DISTRIBUTION_SET + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.DELETE_PREFIX + SpPermission.DISTRIBUTION_SET + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.CREATE_PREFIX + SpPermission.DISTRIBUTION_SET_TYPE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.READ_PREFIX + SpPermission.DISTRIBUTION_SET_TYPE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.UPDATE_PREFIX + SpPermission.DISTRIBUTION_SET_TYPE + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.DELETE_PREFIX + SpPermission.DISTRIBUTION_SET_TYPE + LINE_BREAK;
public static final String ROLLOUT_ADMIN_HIERARCHY =
ROLLOUT_ADMIN + IMPLIES + SpPermission.CREATE_ROLLOUT + LINE_BREAK +
ROLLOUT_ADMIN + IMPLIES + SpPermission.READ_ROLLOUT + LINE_BREAK +
@@ -56,23 +74,17 @@ public final class SpRole {
public static final String TENANT_ADMIN_HIERARCHY =
TENANT_ADMIN + IMPLIES + TARGET_ADMIN + LINE_BREAK +
TENANT_ADMIN + IMPLIES + REPOSITORY_ADMIN + LINE_BREAK +
TENANT_ADMIN + IMPLIES + SpPermission.TENANT_CONFIGURATION + LINE_BREAK +
TENANT_ADMIN + IMPLIES + ROLLOUT_ADMIN + LINE_BREAK;
TENANT_ADMIN + IMPLIES + ROLLOUT_ADMIN + LINE_BREAK +
TENANT_ADMIN + IMPLIES + SpPermission.TENANT_CONFIGURATION + LINE_BREAK;
public static final String SYSTEM_ROLE_HIERARCHY =
SYSTEM_ROLE + IMPLIES + TENANT_ADMIN + LINE_BREAK +
SYSTEM_ROLE + IMPLIES + SpPermission.SYSTEM_ADMIN + LINE_BREAK;
public static final String REPOSITORY_ADMIN_HIERARCHY =
REPOSITORY_ADMIN + IMPLIES + SpPermission.READ_REPOSITORY + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.UPDATE_REPOSITORY + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.CREATE_REPOSITORY + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.DELETE_REPOSITORY + LINE_BREAK +
REPOSITORY_ADMIN + IMPLIES + SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT + LINE_BREAK;
public static final String DEFAULT_ROLE_HIERARCHY =
TARGET_ADMIN_HIERARCHY +
REPOSITORY_ADMIN_HIERARCHY +
ROLLOUT_ADMIN_HIERARCHY +
TENANT_ADMIN_HIERARCHY +
SYSTEM_ROLE_HIERARCHY +
REPOSITORY_ADMIN_HIERARCHY;
SYSTEM_ROLE_HIERARCHY;
// @formatter:on
}