PreAuthorize annotations reviewed and added/adapted where necessary. (#2166)

Default methods implementation from ManagementAPI Interfaces moved to classes.

Co-authored-by: vasilchev <vasil.ilchev@bosch.com>
This commit is contained in:
Vasil Ilchev
2025-01-06 17:15:31 +02:00
committed by GitHub
parent 241a2ae58f
commit 7e7fb0c249
6 changed files with 76 additions and 46 deletions

View File

@@ -403,6 +403,7 @@ public interface DeploymentManagement {
* @return assigned {@link DistributionSet}
* @throws EntityNotFoundException if target with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
Optional<DistributionSet> getAssignedDistributionSet(@NotEmpty String controllerId);
/**
@@ -413,6 +414,7 @@ public interface DeploymentManagement {
* @return installed {@link DistributionSet}
* @throws EntityNotFoundException if target with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
Optional<DistributionSet> getInstalledDistributionSet(@NotEmpty String controllerId);
/**

View File

@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidationCount;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* A DistributionSetInvalidationManagement service provides operations to
@@ -24,6 +25,8 @@ public interface DistributionSetInvalidationManagement {
* cancels all auto assignments referring this {@link DistributionSet} and
* can not be undone. Optionally, all rollouts and actions referring this
* {@link DistributionSet} can be canceled.
* <p>
* {@link PreAuthorize} missing intentionally as it relies on the permission set defined in the management api methods that it calls internally.
*
* @param distributionSetInvalidation defines the {@link DistributionSet} and options what should be
* canceled
@@ -33,6 +36,8 @@ public interface DistributionSetInvalidationManagement {
/**
* Counts all entities for a list of {@link DistributionSet}s that will be
* canceled when invalidation is called for those {@link DistributionSet}s.
* <p>
* {@link PreAuthorize} missing intentionally as it relies on the permission set defined in the management api methods that it calls internally.
*
* @param distributionSetInvalidation defines the {@link DistributionSet} and options what should be
* canceled

View File

@@ -59,8 +59,7 @@ public interface TargetManagement {
* @return number of found {@link Target}s.
* @throws EntityNotFoundException if distribution set with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
long countByAssignedDistributionSet(long distributionSetId);
/**
@@ -81,8 +80,7 @@ public interface TargetManagement {
* @return number of found {@link Target}s.
* @throws EntityNotFoundException if distribution set with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
long countByInstalledDistributionSet(long distributionSetId);
/**
@@ -93,8 +91,7 @@ public interface TargetManagement {
* @return <code>true</code> if a {@link Target} exists.
* @throws EntityNotFoundException if distribution set with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
boolean existsByInstalledOrAssignedDistributionSet(long distributionSetId);
/**
@@ -225,7 +222,7 @@ public interface TargetManagement {
* @return a page of the found {@link Target}s
* @throws EntityNotFoundException if distribution set with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(@NotNull Pageable pageRequest,
long distributionSetId, @NotNull String rsqlParam);
@@ -239,7 +236,7 @@ public interface TargetManagement {
* @return the count of found {@link Target}s
* @throws EntityNotFoundException if distribution set with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
long countByRsqlAndNonDSAndCompatibleAndUpdatable(long distributionSetId, @NotNull String rsqlParam);
/**
@@ -254,17 +251,17 @@ public interface TargetManagement {
* withs
* @return a page of the found {@link Target}s
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ)
Slice<Target> findByTargetFilterQueryAndNotInRolloutGroupsAndCompatibleAndUpdatable(@NotNull Pageable pageRequest,
@NotEmpty Collection<Long> groups, @NotNull String targetFilterQuery,
@NotNull DistributionSetType distributionSetType);
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ)
Slice<Target> findByNotInGEGroupAndNotInActiveActionGEWeightOrInRolloutAndTargetFilterQueryAndCompatibleAndUpdatable(
@NotNull Pageable pageRequest, final long rolloutId, final int weight, final long firstGroupId, @NotNull String targetFilterQuery,
@NotNull DistributionSetType distributionSetType);
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ)
long countByActionsInRolloutGroup(final long rolloutGroupId);
/**
@@ -277,7 +274,7 @@ public interface TargetManagement {
* @param rolloutId rolloutId of the rollout to be retried.
* @return a page of the found {@link Target}s
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ)
Slice<Target> findByFailedRolloutAndNotInRolloutGroups(@NotNull Pageable pageRequest,
@NotEmpty Collection<Long> groups, @NotNull String rolloutId);
@@ -292,7 +289,7 @@ public interface TargetManagement {
* with
* @return count of the found {@link Target}s
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ)
long countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(@NotEmpty Collection<Long> groups,
@NotNull String rsqlParam, @NotNull DistributionSetType distributionSetType);
@@ -305,7 +302,7 @@ public interface TargetManagement {
* @param rolloutId rolloutId of the rollout to be retried.
* @return count of the found {@link Target}s
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ)
long countByFailedRolloutAndNotInRolloutGroups(@NotEmpty Collection<Long> groups, @NotNull String rolloutId);
/**
@@ -526,9 +523,7 @@ public interface TargetManagement {
* @throws EntityNotFoundException if given targetTagId or at least one of the targets do not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
default List<Target> assignTag(@NotEmpty Collection<String> controllerIds, long targetTagId) {
return assignTag(controllerIds, targetTagId, null);
}
List<Target> assignTag(@NotEmpty Collection<String> controllerIds, long targetTagId);
/**
* Un-assign a {@link TargetTag} assignment to given {@link Target}s.
@@ -551,9 +546,7 @@ public interface TargetManagement {
* @throws EntityNotFoundException if given targetTagId or at least one of the targets do not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
default List<Target> unassignTag(@NotEmpty Collection<String> controllerIds, long targetTagId) {
return unassignTag(controllerIds, targetTagId, null);
}
List<Target> unassignTag(@NotEmpty Collection<String> controllerIds, long targetTagId);
/**
* Un-assign a {@link TargetType} assignment to given {@link Target}.

View File

@@ -10,10 +10,6 @@
package org.eclipse.hawkbit.repository;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Map;
import java.util.function.Function;
@@ -22,8 +18,6 @@ import org.eclipse.hawkbit.repository.exception.TenantConfigurationValidatorExce
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.env.Environment;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -126,25 +120,6 @@ public interface TenantConfigurationManagement {
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION_READ)
<T> T getGlobalConfigurationValue(String configurationKeyName, Class<T> propertyType);
// PreAuthorize for TENANT_CONFIGURATION_READ won't be applied but actually we want just read target
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_READ_TARGET)
default Function<Target, PollStatus> pollStatusResolver() {
final Duration pollTime = DurationHelper.formattedStringToDuration(
getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue());
final Duration overdueTime = DurationHelper.formattedStringToDuration(
getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)
.getValue());
return target -> {
final Long lastTargetQuery = target.getLastTargetQuery();
if (lastTargetQuery == null) {
return null;
}
final LocalDateTime currentDate = LocalDateTime.now();
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery),
ZoneId.systemDefault());
final LocalDateTime nextPollDate = lastPollDate.plus(pollTime);
final LocalDateTime overdueDate = nextPollDate.plus(overdueTime);
return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate);
};
}
Function<Target, PollStatus> pollStatusResolver();
}

View File

@@ -530,6 +530,19 @@ public class JpaTargetManagement implements TargetManagement {
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> assignTag(final Collection<String> controllerIds, final long targetTagId,
final Consumer<Collection<String>> notFoundHandler) {
return assignTag0(controllerIds, targetTagId, notFoundHandler);
}
@Override
@Transactional
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> assignTag(final Collection<String> controllerIds, final long targetTagId) {
return assignTag0(controllerIds, targetTagId, null);
}
private List<Target> assignTag0(final Collection<String> controllerIds, final long targetTagId,
final Consumer<Collection<String>> notFoundHandler) {
return updateTag(controllerIds, targetTagId, notFoundHandler, (tag, target) -> {
if (target.getTags().contains(tag)) {
return target;
@@ -546,6 +559,19 @@ public class JpaTargetManagement implements TargetManagement {
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> unassignTag(final Collection<String> controllerIds, final long targetTagId,
final Consumer<Collection<String>> notFoundHandler) {
return unassignTag0(controllerIds, targetTagId, notFoundHandler);
}
@Override
@Transactional
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> unassignTag(final Collection<String> controllerIds, final long targetTagId) {
return unassignTag0(controllerIds, targetTagId, null);
}
private List<Target> unassignTag0(final Collection<String> controllerIds, final long targetTagId,
final Consumer<Collection<String>> notFoundHandler) {
return updateTag(controllerIds, targetTagId, notFoundHandler, (tag, target) -> {
if (target.getTags().contains(tag)) {
target.removeTag(tag);

View File

@@ -14,10 +14,15 @@ import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationPrope
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
@@ -30,10 +35,13 @@ import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantConfiguration;
import org.eclipse.hawkbit.repository.jpa.repository.TenantConfigurationRepository;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.springframework.beans.factory.annotation.Autowired;
@@ -146,6 +154,27 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
return CONVERSION_SERVICE.convert(key.getDefaultValue(), propertyType);
}
@Override
public Function<Target, PollStatus> pollStatusResolver() {
final Duration pollTime = DurationHelper.formattedStringToDuration(
getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue());
final Duration overdueTime = DurationHelper.formattedStringToDuration(
getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)
.getValue());
return target -> {
final Long lastTargetQuery = target.getLastTargetQuery();
if (lastTargetQuery == null) {
return null;
}
final LocalDateTime currentDate = LocalDateTime.now();
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery),
ZoneId.systemDefault());
final LocalDateTime nextPollDate = lastPollDate.plus(pollTime);
final LocalDateTime overdueDate = nextPollDate.plus(overdueTime);
return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate);
};
}
/**
* Validates the data type of the tenant configuration. If it is possible to
* cast to the given data type.