diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAware.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAware.java index 3847313e4..48ac0b1fb 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAware.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAware.java @@ -9,6 +9,8 @@ */ package org.eclipse.hawkbit.tenancy; +import java.util.concurrent.Callable; + import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -30,45 +32,25 @@ public interface TenantAware { String getCurrentUsername(); /** - * Gives the possibility to run a certain code under a specific given {@code tenant}. Only the given {@link TenantRunner} is executed - * under the specific tenant e.g. under control of an {@link ThreadLocal}. After the {@link TenantRunner} it must be ensured that the + * Gives the possibility to run a certain code under a specific given {@code tenant}. Only the given {@link Callable} is executed + * under the specific tenant e.g. under control of an {@link ThreadLocal}. After the {@link Callable} it must be ensured that the * original tenant before this invocation is reset. * * @param tenant the tenant which the specific code should run - * @param tenantRunner the runner which is implemented to run this specific code - * under the given tenant - * @return the return type of the {@link TenantRunner} + * @param callable the runner which is implemented to run this specific code under the given tenant + * @return the return type of the {@link Callable} */ - T runAsTenant(String tenant, TenantRunner tenantRunner); + T runAsTenant(String tenant, Callable callable); /** * Gives the possibility to run a certain code under a specific given {@code tenant} and {@code username}. - * Only the given {@link TenantRunner} is executed under the specific tenant and user e.g. under control of an {@link ThreadLocal}. - * After the {@link TenantRunner} it must be ensured that the original tenant before this invocation is reset. + * Only the given {@link Runnable} is executed under the specific tenant and user e.g. under control of an {@link ThreadLocal}. + * After the {@link Runnable} it must be ensured that the original tenant before this invocation is reset. * * @param tenant the tenant which the specific code should run with * @param username the username which the specific code should run with - * @param tenantRunner the runner which is implemented to run this specific code under the given tenant - * @return the return type of the {@link TenantRunner} */ - T runAsTenantAsUser(String tenant, String username, TenantRunner tenantRunner); - - /** - * An {@link TenantRunner} interface which allows to run specific code under a given tenant by using the - * {@link TenantAware#runAsTenant(String, TenantRunner)}. - * - * @param the return type of the runner - */ - @FunctionalInterface - interface TenantRunner { - - /** - * Called to run specific code and a given tenant. - * - * @return the return of the code block running under a certain tenant - */ - T run(); - } + void runAsTenantAsUser(String tenant, String username, Runnable runnable); /** * Resolves the tenant from the current context. diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/Authenticator.java b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/Authenticator.java index c6f1fe66d..ec3f78603 100644 --- a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/Authenticator.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/Authenticator.java @@ -12,6 +12,7 @@ package org.eclipse.hawkbit.security.controller; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.concurrent.Callable; import lombok.EqualsAndHashCode; import org.eclipse.hawkbit.im.authentication.SpRole; @@ -49,7 +50,7 @@ public interface Authenticator { protected final TenantConfigurationManagement tenantConfigurationManagement; protected final TenantAware tenantAware; protected final SystemSecurityContext systemSecurityContext; - private final TenantAware.TenantRunner isEnabledTenantRunner; + private final Callable isEnabledGetter; protected AbstractAuthenticator( final TenantConfigurationManagement tenantConfigurationManagement, @@ -57,12 +58,12 @@ public interface Authenticator { this.tenantConfigurationManagement = tenantConfigurationManagement; this.tenantAware = tenantAware; this.systemSecurityContext = systemSecurityContext; - isEnabledTenantRunner = () -> systemSecurityContext.runAsSystem( + isEnabledGetter = () -> systemSecurityContext.runAsSystem( () -> tenantConfigurationManagement.getConfigurationValue(getTenantConfigurationKey(), Boolean.class).getValue()); } protected boolean isEnabled(final ControllerSecurityToken securityToken) { - return tenantAware.runAsTenant(securityToken.getTenant(), isEnabledTenantRunner); + return tenantAware.runAsTenant(securityToken.getTenant(), isEnabledGetter); } protected abstract String getTenantConfigurationKey(); diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticator.java b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticator.java index d93d9206d..d11508cdc 100644 --- a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticator.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticator.java @@ -9,6 +9,11 @@ */ package org.eclipse.hawkbit.security.controller; +import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED; +import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY; + +import java.util.concurrent.Callable; + import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.security.SystemSecurityContext; @@ -30,19 +35,18 @@ public class GatewayTokenAuthenticator extends Authenticator.AbstractAuthenticat public static final String GATEWAY_SECURITY_TOKEN_AUTH_SCHEME = "GatewayToken "; private static final int OFFSET_GATEWAY_TOKEN = GATEWAY_SECURITY_TOKEN_AUTH_SCHEME.length(); - private final TenantAware.TenantRunner gatewaySecurityTokenKeyConfigRunner; + private final Callable gatewaySecurityTokenKeyGetter; public GatewayTokenAuthenticator( final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) { super(tenantConfigurationManagement, tenantAware, systemSecurityContext); - gatewaySecurityTokenKeyConfigRunner = () -> { - log.trace("retrieving configuration value for configuration key {}", - TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY); + gatewaySecurityTokenKeyGetter = () -> { + log.trace("retrieving configuration value for configuration key {}", AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY); return systemSecurityContext .runAsSystem(() -> tenantConfigurationManagement - .getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class) + .getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class) .getValue()); }; } @@ -67,7 +71,7 @@ public class GatewayTokenAuthenticator extends Authenticator.AbstractAuthenticat final String presentedToken = authHeader.substring(OFFSET_GATEWAY_TOKEN); // validate if the presented token is the same as the gateway token - return presentedToken.equals(tenantAware.runAsTenant(controllerSecurityToken.getTenant(), gatewaySecurityTokenKeyConfigRunner)) + return presentedToken.equals(tenantAware.runAsTenant(controllerSecurityToken.getTenant(), gatewaySecurityTokenKeyGetter)) ? authenticatedController(controllerSecurityToken.getTenant(), controllerSecurityToken.getControllerId()) : null; } @@ -78,6 +82,6 @@ public class GatewayTokenAuthenticator extends Authenticator.AbstractAuthenticat @Override protected String getTenantConfigurationKey() { - return TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED; + return AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED; } } \ No newline at end of file diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticator.java b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticator.java index 975a6c83e..61b757558 100644 --- a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticator.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticator.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.security.controller; import java.util.Arrays; import java.util.List; +import java.util.concurrent.Callable; import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; @@ -47,7 +48,7 @@ public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthentic // header exists multiple times in the request for all trusted chains. private final String sslIssuerHashBasicHeader; - private final TenantAware.TenantRunner sslIssuerNameConfigTenantRunner; + private final Callable sslIssuerNameConfigGetter; public SecurityHeaderAuthenticator( final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, @@ -56,7 +57,7 @@ public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthentic super(tenantConfigurationManagement, tenantAware, systemSecurityContext); this.caCommonNameHeader = caCommonNameHeader; this.sslIssuerHashBasicHeader = caAuthorityNameHeader; - sslIssuerNameConfigTenantRunner = () -> systemSecurityContext.runAsSystem( + sslIssuerNameConfigGetter = () -> systemSecurityContext.runAsSystem( () -> tenantConfigurationManagement.getConfigurationValue( TenantConfigurationKey.AUTHENTICATION_HEADER_AUTHORITY_NAME, String.class).getValue()); } @@ -81,7 +82,7 @@ public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthentic final String sslIssuerHashValue = getIssuerHashHeader( controllerSecurityToken, - tenantAware.runAsTenant(controllerSecurityToken.getTenant(), sslIssuerNameConfigTenantRunner)); + tenantAware.runAsTenant(controllerSecurityToken.getTenant(), sslIssuerNameConfigGetter)); if (sslIssuerHashValue == null) { log.debug("The request contains the 'common name' header but trusted hash is not found"); return null; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java index d0704d707..dc7314eb4 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SystemManagement.java @@ -47,7 +47,7 @@ public interface SystemManagement { /** * Runs consumer for each tenant as - * {@link TenantAware#runAsTenant(String, org.eclipse.hawkbit.tenancy.TenantAware.TenantRunner)} + * {@link TenantAware#runAsTenant(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 diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DefaultRolloutApprovalStrategy.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DefaultRolloutApprovalStrategy.java index 543511f93..ff4473539 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DefaultRolloutApprovalStrategy.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DefaultRolloutApprovalStrategy.java @@ -15,46 +15,37 @@ import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.repository.RolloutApprovalStrategy; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; -import org.springframework.util.ObjectUtils; /** - * Default implementation of {@link RolloutApprovalStrategy}. Decides whether - * approval is needed based on configuration of the tenant as well as the roles - * of the user who created the Rollout. Provides a no-operation implementation - * of {@link RolloutApprovalStrategy#onApprovalRequired(Rollout)}. + * Default implementation of {@link RolloutApprovalStrategy}. Decides whether approval is needed based on configuration of the tenant as well + * as the roles of the user who created the Rollout. Provides a no-operation implementation of + * {@link RolloutApprovalStrategy#onApprovalRequired(Rollout)}. */ public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy { - private final UserAuthoritiesResolver userAuthoritiesResolver; - private final TenantConfigurationManagement tenantConfigurationManagement; private final SystemSecurityContext systemSecurityContext; DefaultRolloutApprovalStrategy( - final UserAuthoritiesResolver userAuthoritiesResolver, final TenantConfigurationManagement tenantConfigurationManagement, final SystemSecurityContext systemSecurityContext) { - this.userAuthoritiesResolver = userAuthoritiesResolver; this.tenantConfigurationManagement = tenantConfigurationManagement; this.systemSecurityContext = systemSecurityContext; } /** - * Returns true, if rollout approval is enabled and rollout creator doesn't - * have approval role. + * Returns true, if rollout approval is enabled and rollout creator doesn't have approval role. It have to be called in the user context */ @Override public boolean isApprovalNeeded(final Rollout rollout) { - return isApprovalEnabled() && hasNoApproveRolloutPermission(getActorAuthorities(rollout)); + return isApprovalEnabled() && hasNoApproveRolloutPermission( + getCurrentAuthentication().getAuthorities().stream().map(GrantedAuthority::getAuthority).toList()); } /*** @@ -85,19 +76,4 @@ public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy { return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement .getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue()); } - - private Collection getActorAuthorities(final Rollout rollout) { - // rollout state transition from CREATING to CREATED is managed by - // scheduler under SYSTEM user context, thus we get the - // user based on the properties of initially created rollout entity - if (RolloutStatus.CREATING == rollout.getStatus()) { - final String actor = rollout.getLastModifiedBy() != null ? rollout.getLastModifiedBy() : rollout.getCreatedBy(); - if (!ObjectUtils.isEmpty(actor)) { - return systemSecurityContext.runAsSystem(() -> userAuthoritiesResolver.getUserAuthorities(rollout.getTenant(), actor)); - } - } - - return ((User) getCurrentAuthentication().getPrincipal()).getAuthorities().stream() - .map(GrantedAuthority::getAuthority).toList(); - } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRepositoryConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRepositoryConfiguration.java index 9abd21b41..46170cab0 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRepositoryConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRepositoryConfiguration.java @@ -106,7 +106,6 @@ import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.security.SecurityTokenGenerator; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -397,10 +396,9 @@ public class JpaRepositoryConfiguration { */ @Bean @ConditionalOnMissingBean - RolloutApprovalStrategy rolloutApprovalStrategy(final UserAuthoritiesResolver userAuthoritiesResolver, - final TenantConfigurationManagement tenantConfigurationManagement, - final SystemSecurityContext systemSecurityContext) { - return new DefaultRolloutApprovalStrategy(userAuthoritiesResolver, tenantConfigurationManagement, systemSecurityContext); + RolloutApprovalStrategy rolloutApprovalStrategy( + final TenantConfigurationManagement tenantConfigurationManagement, final SystemSecurityContext systemSecurityContext) { + return new DefaultRolloutApprovalStrategy(tenantConfigurationManagement, systemSecurityContext); } /** diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutExecutor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutExecutor.java index f18afdfb7..f51569ad0 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutExecutor.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutExecutor.java @@ -155,10 +155,7 @@ public class JpaRolloutExecutor implements RolloutExecutor { context -> // has stored context - executes it with it contextAware.runInContext(context, () -> execute0(rollout)), () -> // has no stored context - executes it in the tenant & user scope - contextAware.runAsTenantAsUser(contextAware.getCurrentTenant(), rollout.getCreatedBy(), () -> { - execute0(rollout); - return null; - })); + contextAware.runAsTenantAsUser(contextAware.getCurrentTenant(), rollout.getCreatedBy(), () -> execute0(rollout))); } private void execute0(final Rollout rollout) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignChecker.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignChecker.java index 3d612d931..864d4db36 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignChecker.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignChecker.java @@ -142,10 +142,7 @@ public class AutoAssignChecker implements AutoAssignExecutor { () -> // has no stored context - executes it in the tenant & user scope contextAware.runAsTenantAsUser( contextAware.getCurrentTenant(), - getAutoAssignmentInitiatedBy(filterQuery), () -> { - consumer.accept(filterQuery); - return null; - }) + getAutoAssignmentInitiatedBy(filterQuery), () -> consumer.accept(filterQuery)) ); } catch (final RuntimeException ex) { if (log.isDebugEnabled()) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantConfigurationManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantConfigurationManagement.java index 770ac50eb..f90030b6a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantConfigurationManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantConfigurationManagement.java @@ -9,6 +9,7 @@ */ package org.eclipse.hawkbit.repository.jpa.management; +import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_GATEWAY_SECURITY_TOKEN; import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY; import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED; import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED; @@ -28,7 +29,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.event.remote.TenantConfigurationDeletedEvent; @@ -248,10 +248,9 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana private void checkAccess(final String configurationKeyName) { if (AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY.equalsIgnoreCase(configurationKeyName)) { final SystemSecurityContext systemSecurityContext = SystemSecurityContextHolder.getInstance().getSystemSecurityContext(); - if (!systemSecurityContext.isCurrentThreadSystemCode() && - !systemSecurityContext.hasPermission(SpPermission.READ_GATEWAY_SECURITY_TOKEN)) { + if (!SystemSecurityContext.isCurrentThreadSystemCode() && !systemSecurityContext.hasPermission(READ_GATEWAY_SECURITY_TOKEN)) { throw new InsufficientPermissionException( - "Can't read gateway security token! " + SpPermission.READ_GATEWAY_SECURITY_TOKEN + " is required!"); + "Can't read gateway security token! " + READ_GATEWAY_SECURITY_TOKEN + " is required!"); } } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index ea76e53df..7df0df7ba 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -216,7 +216,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw @Override public String getSecurityToken() { final SystemSecurityContext systemSecurityContext = SystemSecurityContextHolder.getInstance().getSystemSecurityContext(); - if (systemSecurityContext.isCurrentThreadSystemCode() || systemSecurityContext.hasPermission(SpPermission.READ_TARGET_SECURITY_TOKEN)) { + if (SystemSecurityContext.isCurrentThreadSystemCode() || systemSecurityContext.hasPermission(SpPermission.READ_TARGET_SECURITY_TOKEN)) { return securityToken; } return null; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignCheckerTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignCheckerTest.java index 0fedb3b00..f87618839 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignCheckerTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autoassign/AutoAssignCheckerTest.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.autoassign; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -27,8 +28,8 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.model.DeploymentRequest; import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -47,9 +48,9 @@ import org.springframework.transaction.PlatformTransactionManager; class AutoAssignCheckerTest { @Mock - private TargetFilterQueryManagement targetFilterQueryManagement; + private TargetFilterQueryManagement targetFilterQueryManagement; @Mock - private TargetManagement targetManagement; + private TargetManagement targetManagement; @Mock private DeploymentManagement deploymentManagement; @Mock @@ -57,12 +58,12 @@ class AutoAssignCheckerTest { @Mock private ContextAware contextAware; - private AutoAssignChecker sut; + private AutoAssignChecker autoAssignChecker; @BeforeEach void before() { - sut = new AutoAssignChecker(targetFilterQueryManagement, targetManagement, deploymentManagement, - transactionManager, contextAware); + autoAssignChecker = new AutoAssignChecker( + targetFilterQueryManagement, targetManagement, deploymentManagement, transactionManager, contextAware); } /** @@ -75,18 +76,15 @@ class AutoAssignCheckerTest { final long ds = getRandomLong(); final TargetFilterQuery matching = mockFilterQuery(ds); final TargetFilterQuery notMatching = mockFilterQuery(ds); - when(targetFilterQueryManagement.findWithAutoAssignDS(any())) - .thenReturn(new SliceImpl<>(Arrays.asList(notMatching, matching))); - - when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, ds, matching.getQuery())) - .thenReturn(true); + when(targetFilterQueryManagement.findWithAutoAssignDS(any())).thenReturn(new SliceImpl<>(Arrays.asList(notMatching, matching))); + when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, ds, matching.getQuery())).thenReturn(true); when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, ds, notMatching.getQuery())) .thenReturn(false); - sut.checkSingleTarget(target); + autoAssignChecker.checkSingleTarget(target); - verify(deploymentManagement).assignDistributionSets(eq(matching.getAutoAssignInitiatedBy()), - Mockito.argThat(deployReqMatcher(target, ds)), any()); + verify(deploymentManagement).assignDistributionSets( + eq(matching.getAutoAssignInitiatedBy()), Mockito.argThat(deployReqMatcher(target, ds)), any()); Mockito.verifyNoMoreInteractions(deploymentManagement); } @@ -118,8 +116,9 @@ class AutoAssignCheckerTest { private void mockRunningAsNonSystem() { when(contextAware.getCurrentTenant()).thenReturn(getRandomString()); - when(contextAware.runAsTenantAsUser(any(String.class), any(String.class), any(TenantAware.TenantRunner.class))) - .thenAnswer(i -> ((TenantAware.TenantRunner) i.getArgument(2)).run()); + doAnswer(i -> { + ((Runnable) i.getArgument(2)).run(); + return null; + }).when(contextAware).runAsTenantAsUser(any(String.class), any(String.class), any(Runnable.class)); } - -} +} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java index 2bcc32003..31be06859 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java @@ -15,6 +15,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.Callable; import java.util.function.Function; import java.util.function.Supplier; @@ -106,12 +107,21 @@ public class SecurityContextTenantAware implements ContextAware { } @Override - public T runAsTenant(final String tenant, final TenantRunner tenantRunner) { - return runInContext(buildUserSecurityContext(tenant, SYSTEM_USER, SYSTEM_AUTHORITIES), tenantRunner::run); + @SuppressWarnings("java:S112") // java:S112 - it is generic class so a generic exception is fine + public T runAsTenant(final String tenant, final Callable callable) { + return runInContext(buildUserSecurityContext(tenant, SYSTEM_USER, SYSTEM_AUTHORITIES), () -> { + try { + return callable.call(); + } catch (final RuntimeException e) { + throw e; + } catch (final Exception e) { + throw new RuntimeException(e); + } + }); } @Override - public T runAsTenantAsUser(final String tenant, final String username, final TenantRunner tenantRunner) { + public void runAsTenantAsUser(final String tenant, final String username, final Runnable runnable) { Objects.requireNonNull(tenant); Objects.requireNonNull(username); @@ -119,7 +129,10 @@ public class SecurityContextTenantAware implements ContextAware { () -> authoritiesResolver.getUserAuthorities(tenant, username).stream() .map(SimpleGrantedAuthority::new) .toList()); - return runInContext(buildUserSecurityContext(tenant, username, authorities), tenantRunner::run); + runInContext(buildUserSecurityContext(tenant, username, authorities), () -> { + runnable.run(); + return null; + }); } @Override @@ -151,11 +164,11 @@ public class SecurityContextTenantAware implements ContextAware { } } - private static T runAsSystem(final TenantRunner tenantRunner) { + private static T runAsSystem(final Callable callable) { final SecurityContext currentContext = SecurityContextHolder.getContext(); SystemSecurityContext.setSystemContext(currentContext); try { - return MdcHandler.getInstance().callWithAuthRE(tenantRunner::run); + return MdcHandler.getInstance().callWithAuthRE(callable); } finally { SecurityContextHolder.setContext(currentContext); } diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SystemCodeAuthenticationTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SystemCodeAuthenticationTest.java index a818e95ac..7d879c2dd 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SystemCodeAuthenticationTest.java +++ b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SystemCodeAuthenticationTest.java @@ -15,7 +15,9 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.List; +import java.util.concurrent.Callable; +import lombok.SneakyThrows; import org.assertj.core.api.Assertions; import org.eclipse.hawkbit.tenancy.TenantAware; import org.junit.jupiter.api.Test; @@ -39,14 +41,15 @@ class SystemCodeAuthenticationTest { return "user"; } + @SneakyThrows @Override - public T runAsTenant(final String tenant, final TenantRunner tenantRunner) { - return tenantRunner.run(); + public T runAsTenant(final String tenant, final Callable callable) { + return callable.call(); } @Override - public T runAsTenantAsUser(final String tenant, final String username, final TenantRunner tenantRunner) { - return tenantRunner.run(); + public void runAsTenantAsUser(final String tenant, final String username, final Runnable runnable) { + runnable.run(); } });