Refactor hawkbit core and security (#2833)

* Refactor hawkbit core and security

* improve access to the base core features - static
* thus easiear access
* and less boilerplate passing of instances

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>

* Refactor context classes

* make JSON context serialization default

* AccessContext

* Split hawkbit-security-core to other modules and remove it

---------

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-11-27 13:07:49 +02:00
committed by GitHub
parent 58dbc32a80
commit f6f62db0ad
274 changed files with 2534 additions and 4458 deletions

View File

@@ -17,8 +17,8 @@ import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.artifact.exception.ArtifactUploadFailedException;
import org.eclipse.hawkbit.artifact.model.ArtifactStream;
import org.eclipse.hawkbit.artifact.model.StoredArtifactInfo;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidMd5HashException;

View File

@@ -15,11 +15,10 @@ import java.util.Optional;
import jakarta.validation.constraints.NotEmpty;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.security.access.prepost.PreAuthorize;
/**
@@ -40,7 +39,7 @@ public interface ConfirmationManagement extends PermissionSupport {
* Activate auto confirmation for a given controller ID. In case auto confirmation is active already, this method will fail with an exception.
*
* @param controllerId to activate the feature for
* @param initiator who initiated this operation. If 'null' we will take the current user from {@link TenantAware#getCurrentUsername()}
* @param initiator who initiated this operation.
* @param remark optional field to set a remark
* @return the persisted {@link AutoConfirmationStatus}
*/

View File

@@ -20,7 +20,7 @@ import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;

View File

@@ -9,13 +9,11 @@
*/
package org.eclipse.hawkbit.repository;
import static org.eclipse.hawkbit.im.authentication.SpPermission.CREATE_ROLLOUT;
import static org.eclipse.hawkbit.im.authentication.SpPermission.DISTRIBUTION_SET;
import static org.eclipse.hawkbit.im.authentication.SpPermission.HANDLE_ROLLOUT;
import static org.eclipse.hawkbit.im.authentication.SpPermission.ROLLOUT;
import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_ROLLOUT;
import static org.eclipse.hawkbit.im.authentication.SpringEvalExpressions.HAS_READ_REPOSITORY;
import static org.eclipse.hawkbit.im.authentication.SpringEvalExpressions.HAS_UPDATE_REPOSITORY;
import static org.eclipse.hawkbit.auth.SpPermission.CREATE_ROLLOUT;
import static org.eclipse.hawkbit.auth.SpPermission.DISTRIBUTION_SET;
import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_ROLLOUT;
import static org.eclipse.hawkbit.auth.SpringEvalExpressions.HAS_READ_REPOSITORY;
import static org.eclipse.hawkbit.auth.SpringEvalExpressions.HAS_UPDATE_REPOSITORY;
import java.util.Collection;
import java.util.List;
@@ -27,8 +25,8 @@ import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
@@ -51,6 +49,7 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.lang.Nullable;
import org.springframework.security.access.prepost.PreAuthorize;
/**
@@ -70,23 +69,6 @@ public interface DeploymentManagement extends PermissionSupport {
* Assigns {@link DistributionSet}s to {@link Target}s according to the {@link DeploymentRequest}.
*
* @param deploymentRequests information about all target-ds-assignments that shall be made
* @return the list of assignment results
* @throws IncompleteDistributionSetException if mandatory {@link SoftwareModuleType} are not assigned as
* defined by the {@link DistributionSetType}.
* @throws EntityNotFoundException if either provided {@link DistributionSet} or {@link Target}s do not exist
* @throws AssignmentQuotaExceededException if the maximum number of targets the distribution set can be
* assigned to at once is exceeded
* @throws MultiAssignmentIsNotEnabledException if the request results in multiple assignments to the same
* target and multi-assignment is disabled
*/
@PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET)
List<DistributionSetAssignmentResult> assignDistributionSets(@Valid @NotEmpty List<DeploymentRequest> deploymentRequests);
/**
* Assigns {@link DistributionSet}s to {@link Target}s according to the {@link DeploymentRequest}.
*
* @param initiatedBy the username of the user who initiated the assignment
* @param deploymentRequests information about all target-ds-assignments that shall be made
* @param actionMessage an optional message for the action status
* @return the list of assignment results
* @throws IncompleteDistributionSetException if mandatory {@link SoftwareModuleType} are not assigned as
@@ -99,7 +81,7 @@ public interface DeploymentManagement extends PermissionSupport {
*/
@PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET)
List<DistributionSetAssignmentResult> assignDistributionSets(
String initiatedBy, @Valid @NotEmpty List<DeploymentRequest> deploymentRequests, String actionMessage);
@Valid @NotEmpty List<DeploymentRequest> deploymentRequests, @Nullable String actionMessage);
/**
* Registers "offline" assignments. "offline" assignment means adding a completed action for a {@link DistributionSet} to a {@link Target}.
@@ -123,9 +105,6 @@ public interface DeploymentManagement extends PermissionSupport {
* @throws MultiAssignmentIsNotEnabledException if the request results in multiple assignments to the same
* target and multi-assignment is disabled
*/
@PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET)
List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(String initiatedBy, Collection<Entry<String, Long>> assignments);
@PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET)
List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(Collection<Entry<String, Long>> assignments);

View File

@@ -9,8 +9,8 @@
*/
package org.eclipse.hawkbit.repository;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
import org.springframework.security.access.prepost.PreAuthorize;

View File

@@ -9,13 +9,12 @@
*/
package org.eclipse.hawkbit.repository;
import static org.eclipse.hawkbit.im.authentication.SpringEvalExpressions.HAS_READ_REPOSITORY;
import static org.eclipse.hawkbit.im.authentication.SpringEvalExpressions.HAS_UPDATE_REPOSITORY;
import static org.eclipse.hawkbit.auth.SpringEvalExpressions.HAS_READ_REPOSITORY;
import static org.eclipse.hawkbit.auth.SpringEvalExpressions.HAS_UPDATE_REPOSITORY;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import jakarta.validation.constraints.NotEmpty;
@@ -27,7 +26,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;

View File

@@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Tag;

View File

@@ -21,8 +21,8 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;

View File

@@ -15,7 +15,7 @@ import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;

View File

@@ -19,7 +19,7 @@ import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;

View File

@@ -9,7 +9,7 @@
*/
package org.eclipse.hawkbit.repository;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup;

View File

@@ -9,12 +9,10 @@
*/
package org.eclipse.hawkbit.repository;
import java.util.Optional;
import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;

View File

@@ -9,8 +9,7 @@
*/
package org.eclipse.hawkbit.repository;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target;

View File

@@ -28,8 +28,8 @@ import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.security.crypto.codec.Hex;
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
import org.springframework.security.crypto.keygen.KeyGenerators;
/**
* A singleton bean which holds the {@link SecurityTokenGenerator} and make it
* accessible to beans which are not managed by spring, e.g. JPA entities.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings("java:S6548") // java:S6548 - singleton holder ensures static access to spring resources in some places
public final class SecurityTokenGenerator {
private static final int TOKEN_LENGTH = 16;
private static final BytesKeyGenerator SECURE_RANDOM = KeyGenerators.secureRandom(TOKEN_LENGTH);
/**
* Generates a random secure token of {@link #TOKEN_LENGTH} bytes length as hexadecimal string.
*
* @return a new generated random alphanumeric string.
*/
public static String generateToken() {
return new String(Hex.encode(SECURE_RANDOM.generateKey()));
}
}

View File

@@ -1,49 +0,0 @@
/**
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
import org.springframework.beans.factory.annotation.Autowired;
/**
* A singleton bean which holds the {@link SecurityTokenGenerator} and make it
* accessible to beans which are not managed by spring, e.g. JPA entities.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings("java:S6548") // java:S6548 - singleton holder ensures static access to spring resources in some places
public final class SecurityTokenGeneratorHolder {
private static final SecurityTokenGeneratorHolder SINGLETON = new SecurityTokenGeneratorHolder();
private SecurityTokenGenerator securityTokenGenerator;
/**
* @return a singleton instance of the security token generator holder.
*/
public static SecurityTokenGeneratorHolder getInstance() {
return SINGLETON;
}
@Autowired // spring setter injection
public void setSecurityTokenGenerator(final SecurityTokenGenerator securityTokenGenerator) {
this.securityTokenGenerator = securityTokenGenerator;
}
/**
* delegates to {@link SecurityTokenGenerator#generateToken()}.
*
* @return the result {@link SecurityTokenGenerator#generateToken()}
*/
public String generateToken() {
return securityTokenGenerator.generateToken();
}
}

View File

@@ -20,8 +20,8 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.NamedEntity;

View File

@@ -20,8 +20,8 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Type;

View File

@@ -13,14 +13,12 @@ import java.util.function.Consumer;
import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.context.AccessContext;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.TenantMetaData;
import org.eclipse.hawkbit.repository.model.report.SystemUsageReport;
import org.eclipse.hawkbit.repository.model.report.SystemUsageReportWithTenants;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -30,14 +28,6 @@ import org.springframework.security.access.prepost.PreAuthorize;
*/
public interface SystemManagement {
/**
* Deletes all data related to a given tenant.
*
* @param tenant to delete
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
void deleteTenant(@NotNull String tenant);
/**
* @param pageable for paging information
* @return list of all tenant names in the system.
@@ -47,7 +37,7 @@ public interface SystemManagement {
/**
* Runs consumer for each tenant as
* {@link TenantAware#runAsTenant(String, java.util.concurrent.Callable)}
* {@link AccessContext#asSystemAsTenant(String, java.util.concurrent.Callable)}
* silently (i.e. exceptions will be logged but operations will continue for further tenants).
*
* @param consumer to run as tenant
@@ -56,37 +46,15 @@ public interface SystemManagement {
void forEachTenant(Consumer<String> consumer);
/**
* Calculated system usage statistics, both overall for the entire system and per tenant;
*
* @return SystemUsageReport of the current system
* @return {@link TenantMetaData} of {@link AccessContext#tenant()}
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
SystemUsageReportWithTenants getSystemUsageStatisticsWithTenants();
/**
* Calculated overall system usage statistics
*
* @return SystemUsageReport of the current system
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
SystemUsageReport getSystemUsageStatistics();
/**
* @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()}
*/
@PreAuthorize("hasAuthority('" + SpPermission.READ_DISTRIBUTION_SET + "')" + " or "
+ "hasAuthority('READ_" + SpPermission.TARGET + "')" + " or "
+ "hasAuthority('READ_" + SpPermission.TENANT_CONFIGURATION + "')" + " or "
+ SpringEvalExpressions.IS_CONTROLLER)
@PreAuthorize("hasAuthority('" + SpPermission.READ_DISTRIBUTION_SET + "')" + " or " + "hasAuthority('READ_" + SpPermission.TARGET + "')" + " or " + "hasAuthority('READ_" + SpPermission.TENANT_CONFIGURATION + "')" + " or " + SpringEvalExpressions.IS_CONTROLLER)
TenantMetaData getTenantMetadata();
/**
* @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()} without details ({@link TenantMetaData#getDefaultDsType()})
* @return {@link TenantMetaData} of {@link AccessContext#tenant()} without details ({@link TenantMetaData#getDefaultDsType()})
*/
@PreAuthorize("hasAuthority('" + SpPermission.READ_DISTRIBUTION_SET + "')" + " or "
+ "hasAuthority('READ_" + SpPermission.TARGET + "')" + " or "
+ "hasAuthority('READ_" + SpPermission.TENANT_CONFIGURATION + "')" + " or "
+ SpringEvalExpressions.IS_CONTROLLER)
@PreAuthorize("hasAuthority('" + SpPermission.READ_DISTRIBUTION_SET + "')" + " or " + "hasAuthority('READ_" + SpPermission.TARGET + "')" + " or " + "hasAuthority('READ_" + SpPermission.TENANT_CONFIGURATION + "')" + " or " + SpringEvalExpressions.IS_CONTROLLER)
TenantMetaData getTenantMetadataWithoutDetails();
/**
@@ -113,4 +81,12 @@ public interface SystemManagement {
*/
@PreAuthorize("hasAuthority('UPDATE_" + SpPermission.TENANT_CONFIGURATION + "')")
TenantMetaData updateTenantMetadata(long defaultDsType);
/**
* Deletes all data related to a given tenant.
*
* @param tenant to delete
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
void deleteTenant(@NotNull String tenant);
}

View File

@@ -22,8 +22,8 @@ import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;

View File

@@ -9,9 +9,9 @@
*/
package org.eclipse.hawkbit.repository;
import static org.eclipse.hawkbit.im.authentication.SpringEvalExpressions.HAS_DELETE_REPOSITORY;
import static org.eclipse.hawkbit.im.authentication.SpringEvalExpressions.HAS_READ_REPOSITORY;
import static org.eclipse.hawkbit.im.authentication.SpringEvalExpressions.HAS_UPDATE_REPOSITORY;
import static org.eclipse.hawkbit.auth.SpringEvalExpressions.HAS_DELETE_REPOSITORY;
import static org.eclipse.hawkbit.auth.SpringEvalExpressions.HAS_READ_REPOSITORY;
import static org.eclipse.hawkbit.auth.SpringEvalExpressions.HAS_UPDATE_REPOSITORY;
import java.util.Collection;
import java.util.List;
@@ -29,8 +29,8 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
@@ -466,7 +466,7 @@ public interface TargetManagement<T extends Target>
: controllerId
: builder.name;
securityToken = ObjectUtils.isEmpty(builder.securityToken)
? SecurityTokenGeneratorHolder.getInstance().generateToken()
? SecurityTokenGenerator.generateToken()
: builder.securityToken;
}
}

View File

@@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.TargetTag;

View File

@@ -9,7 +9,7 @@
*/
package org.eclipse.hawkbit.repository;
import static org.eclipse.hawkbit.im.authentication.SpringEvalExpressions.HAS_READ_REPOSITORY;
import static org.eclipse.hawkbit.auth.SpringEvalExpressions.HAS_READ_REPOSITORY;
import java.util.Collection;
import java.util.Collections;
@@ -24,8 +24,8 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.TargetTypeKeyOrNameRequiredException;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.NamedEntity;

View File

@@ -13,8 +13,8 @@ import java.io.Serializable;
import java.util.Map;
import java.util.function.Function;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.TenantConfigurationValidatorException;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Target;

View File

@@ -9,8 +9,8 @@
*/
package org.eclipse.hawkbit.repository;
import org.eclipse.hawkbit.im.authentication.SpRole;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.auth.SpRole;
import org.eclipse.hawkbit.auth.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.report.TenantUsage;
import org.springframework.security.access.prepost.PreAuthorize;

View File

@@ -9,9 +9,6 @@
*/
package org.eclipse.hawkbit.repository;
import java.util.Arrays;
import java.util.Optional;
/**
* Enumerates the supported update modes. Each mode represents an attribute update strategy.
*

View File

@@ -15,7 +15,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.context.ApplicationEvent;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")

View File

@@ -17,7 +17,6 @@ import lombok.NoArgsConstructor;
import lombok.ToString;
import org.eclipse.hawkbit.repository.event.entity.EntityDeletedEvent;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager;
import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager.CacheEvictEvent;
/**

View File

@@ -1,42 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.helper;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
/**
* A singleton bean which holds {@link SystemSecurityContext} service and makes it accessible to beans which are not
* managed by spring, e.g. JPA entities.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings("java:S6548") // java:S6548 - singleton holder ensures static access to spring resources in some places
public final class SystemSecurityContextHolder {
private static final SystemSecurityContextHolder SINGLETON = new SystemSecurityContextHolder();
@Getter
private SystemSecurityContext systemSecurityContext;
/**
* @return the singleton {@link SystemSecurityContextHolder} instance
*/
public static SystemSecurityContextHolder getInstance() {
return SINGLETON;
}
@Autowired // spring setter injection
public void setSystemSecurityContext(final SystemSecurityContext systemSecurityContext) {
this.systemSecurityContext = systemSecurityContext;
}
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.helper;
import static org.eclipse.hawkbit.context.AccessContext.asSystem;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED;
import java.io.Serializable;
import java.util.Objects;
import java.util.function.Function;
import lombok.NoArgsConstructor;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Target;
/**
* A collection of static helper methods for the tenant configuration
*/
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
public final class TenantConfigHelper {
private static TenantConfigurationManagement tenantConfigurationManagement;
// method to be initialized by the TenantConfigurationManagement or TenantConfigurationManagement creator
// it will be accessed directly and used so shall be fully initialized instance, i.e. a bean in order to onore things
// like @PreAuthorize, @Transactional etc.
public static void setTenantConfigurationManagement(final TenantConfigurationManagement tenantConfigurationManagement) {
TenantConfigHelper.tenantConfigurationManagement = tenantConfigurationManagement;
}
public static TenantConfigurationManagement getTenantConfigurationManagement() {
return Objects.requireNonNull(tenantConfigurationManagement, "TenantConfigurationManagement has not been initialized");
}
public static <T extends Serializable> T getAsSystem(final String key, final Class<T> valueType) {
return asSystem(() -> getTenantConfigurationManagement().getConfigurationValue(key, valueType).getValue());
}
public static boolean isMultiAssignmentsEnabled() {
return getAsSystem(MULTI_ASSIGNMENTS_ENABLED, Boolean.class);
}
public static boolean isUserConfirmationFlowEnabled() {
return getAsSystem(USER_CONFIRMATION_FLOW_ENABLED, Boolean.class);
}
public static Function<Target, PollStatus> pollStatusResolver() {
return getTenantConfigurationManagement().pollStatusResolver();
}
}

View File

@@ -1,42 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.helper;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.springframework.beans.factory.annotation.Autowired;
/**
* A singleton bean which holds {@link TenantConfigurationManagement} service and makes it accessible to beans which are
* not managed by spring, e.g. JPA entities.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings("java:S6548") // java:S6548 - singleton holder ensures static access to spring resources in some places
public final class TenantConfigurationManagementHolder {
private static final TenantConfigurationManagementHolder SINGLETON = new TenantConfigurationManagementHolder();
@Getter
private TenantConfigurationManagement tenantConfigurationManagement;
/**
* @return the singleton {@link TenantConfigurationManagementHolder} instance
*/
public static TenantConfigurationManagementHolder getInstance() {
return SINGLETON;
}
@Autowired // spring setter injection
public void setTenantConfigurationManagement(final TenantConfigurationManagement tenantConfigurationManagement) {
this.tenantConfigurationManagement = tenantConfigurationManagement;
}
}

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.model;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.auth.SpPermission;
import org.eclipse.hawkbit.repository.Identifiable;
/**
@@ -61,7 +62,7 @@ public interface Target extends NamedEntity, Identifiable<Long> {
/**
* @return the securityToken if the current security context contains the necessary permission
* {@link org.eclipse.hawkbit.im.authentication.SpPermission#READ_TARGET_SECURITY_TOKEN}
* {@link SpPermission#READ_TARGET_SECURITY_TOKEN}
* or the current context is executed as system code, otherwise {@code null}.
*/
String getSecurityToken();

View File

@@ -14,8 +14,7 @@ import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationPrope
import java.time.Duration;
import org.eclipse.hawkbit.repository.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.helper.TenantConfigHelper;
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
import org.eclipse.hawkbit.tenancy.configuration.PollingTime;
import org.springframework.util.PropertyPlaceholderHelper;
@@ -81,8 +80,6 @@ public class VirtualPropertyResolver {
}
private static String getRawStringForKey(final String key) {
return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(
() -> TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement()
.getConfigurationValue(key, String.class).getValue());
return TenantConfigHelper.getAsSystem(key, String.class);
}
}

View File

@@ -58,7 +58,7 @@ public class TenantConfigurationProperties {
}
/**
* Tenant specific configurations which can be configured for each tenant separately by means of override of the system defaults.
* AccessContext specific configurations which can be configured for each tenant separately by means of override of the system defaults.
*/
@Data
@ToString
@@ -127,7 +127,7 @@ public class TenantConfigurationProperties {
/**
* Switch to enable/disable the user-confirmation flow
*/
public static final String USER_CONFIRMATION_ENABLED = "user.confirmation.flow.enabled";
public static final String USER_CONFIRMATION_FLOW_ENABLED = "user.confirmation.flow.enabled";
/**
* Switch to enable/disable the implicit locking
*/

View File

@@ -1,76 +0,0 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.utils;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.USER_CONFIRMATION_ENABLED;
import java.io.Serializable;
import java.util.function.Function;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.security.SystemSecurityContext;
/**
* A collection of static helper methods for the tenant configuration
*/
public final class TenantConfigHelper {
private final TenantConfigurationManagement tenantConfigurationManagement;
private final SystemSecurityContext systemSecurityContext;
private TenantConfigHelper(
final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.systemSecurityContext = systemSecurityContext;
this.tenantConfigurationManagement = tenantConfigurationManagement;
}
/**
* Setting the context of the tenant.
*
* @param systemSecurityContext Security context used to get the tenant and for execution
* @param tenantConfigurationManagement to get the value from
* @return is active
*/
public static TenantConfigHelper usingContext(
final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
return new TenantConfigHelper(systemSecurityContext, tenantConfigurationManagement);
}
public <T extends Serializable> T getConfigValue(final String key, final Class<T> valueType) {
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue());
}
/**
* Is multi-assignments enabled for the current tenant
*
* @return is active
*/
public boolean isMultiAssignmentsEnabled() {
return getConfigValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class);
}
/**
* Is confirmation flow enabled for the current tenant
*
* @return is enabled
*/
public boolean isConfirmationFlowEnabled() {
return getConfigValue(USER_CONFIRMATION_ENABLED, Boolean.class);
}
public Function<Target, PollStatus> pollStatusResolver() {
return tenantConfigurationManagement.pollStatusResolver();
}
}