diff --git a/hawkbit-autoconfigure/pom.xml b/hawkbit-autoconfigure/pom.xml index eaa9ed7d0..6822682cd 100644 --- a/hawkbit-autoconfigure/pom.xml +++ b/hawkbit-autoconfigure/pom.xml @@ -29,14 +29,12 @@ true - org.eclipse.hawkbit - hawkbit-repository-jpa - ${project.version} - true + org.springframework.security + spring-security-web org.eclipse.hawkbit - hawkbit-security-core + hawkbit-repository-jpa ${project.version} true diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java index 62508bee5..5910313a2 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java @@ -9,30 +9,13 @@ */ package org.eclipse.hawkbit.autoconfigure.security; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import java.util.Optional; -import org.eclipse.hawkbit.ContextAware; -import org.eclipse.hawkbit.audit.AuditContextProvider; import org.eclipse.hawkbit.audit.AuditLoggingAspect; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.RepositoryConfiguration; -import org.eclipse.hawkbit.tenancy.TenantAware.DefaultTenantResolver; -import org.eclipse.hawkbit.tenancy.TenantAware.TenantResolver; -import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties; -import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties.User; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.security.InMemoryUserAuthoritiesResolver; -import org.eclipse.hawkbit.security.MdcHandler; -import org.eclipse.hawkbit.security.SecurityContextSerializer; -import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.security.SecurityTokenGenerator; -import org.eclipse.hawkbit.security.SpringSecurityAuditorAware; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; -import org.springframework.beans.factory.annotation.Autowired; +import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.security.SecurityProperties; @@ -41,14 +24,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.domain.AuditorAware; -import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; -import org.springframework.util.CollectionUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for security. @@ -58,48 +39,6 @@ import org.springframework.util.CollectionUtils; @Import(RepositoryConfiguration.class) public class SecurityAutoConfiguration { - /** - * Creates a {@link ContextAware} (hence {@link TenantAware}) bean based on the given {@link UserAuthoritiesResolver}, - * {@link SecurityContextSerializer} and {@link TenantResolver}. - * - * @param authoritiesResolver The user authorities/roles resolver - * @param securityContextSerializer The security context serializer (optional, if not found the default {@link SecurityContextSerializer#NOP} is used). - * @param tenantResolver The tenant resolver (optional, if not found the default {@link DefaultTenantResolver} is used). - * @return the {@link ContextAware} singleton bean. - */ - @Bean - @ConditionalOnMissingBean - public ContextAware contextAware( - final UserAuthoritiesResolver authoritiesResolver, - @Autowired(required = false) final SecurityContextSerializer securityContextSerializer, - @Autowired(required = false) final TenantResolver tenantResolver) { - return new SecurityContextTenantAware(authoritiesResolver, securityContextSerializer, tenantResolver); - } - - /** - * Creates a {@link UserAuthoritiesResolver} bean that is responsible for resolving user authorities/roles. - * - * @param securityProperties The Spring {@link SecurityProperties} for the security user - * @param tenantAwareUserProperties The {@link TenantAwareUserProperties} for the managed users - * @return an {@link InMemoryUserAuthoritiesResolver} bean - */ - @Bean - @ConditionalOnMissingBean - public UserAuthoritiesResolver inMemoryAuthoritiesResolver( - final SecurityProperties securityProperties, - final TenantAwareUserProperties tenantAwareUserProperties) { - final Map tenantAwareUsers = tenantAwareUserProperties.getUser(); - final Map> usersToPermissions; - if (!CollectionUtils.isEmpty(tenantAwareUsers)) { - usersToPermissions = tenantAwareUsers.entrySet().stream().collect( - Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getRoles())); - } else { - usersToPermissions = Collections.singletonMap(securityProperties.getUser().getName(), - securityProperties.getUser().getRoles()); - } - return new InMemoryUserAuthoritiesResolver(usersToPermissions); - } - /** * Creates the auditor aware. * @@ -108,13 +47,7 @@ public class SecurityAutoConfiguration { @Bean @ConditionalOnMissingBean public AuditorAware auditorAware() { - return new SpringSecurityAuditorAware(); - } - - @Bean - @ConditionalOnMissingBean - public AuditContextProvider auditContextProvider() { - return AuditContextProvider.getInstance(); + return () -> Optional.ofNullable(AccessContext.actor()); } @Bean @@ -123,28 +56,6 @@ public class SecurityAutoConfiguration { return new AuditLoggingAspect(); } - /** - * @param tenantAware singleton bean - * @return tenantAware {@link SystemSecurityContext} - */ - @Bean - @ConditionalOnMissingBean - public SystemSecurityContext systemSecurityContext(final TenantAware tenantAware, final RoleHierarchy roleHierarchy) { - return new SystemSecurityContext(tenantAware, roleHierarchy); - } - - @Bean - @ConditionalOnMissingBean - public MdcHandler mdcHandler() { - return MdcHandler.getInstance(); - } - - @Bean - @ConditionalOnMissingBean - public SecurityTokenGenerator securityTokenGenerator() { - return new SecurityTokenGenerator(); - } - @Bean @ConditionalOnMissingBean public AuthenticationSuccessHandler authenticationSuccessHandler() { diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/StaticUserManagementAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/StaticUserManagementAutoConfiguration.java index f83c75e50..014b072c3 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/StaticUserManagementAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/StaticUserManagementAutoConfiguration.java @@ -9,7 +9,7 @@ */ package org.eclipse.hawkbit.autoconfigure.security; -import org.eclipse.hawkbit.im.authentication.StaticAuthenticationProvider; +import org.eclipse.hawkbit.auth.StaticAuthenticationProvider; import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; diff --git a/hawkbit-autoconfigure/src/main/resources/hawkbit-artifactdl-defaults.properties b/hawkbit-autoconfigure/src/main/resources/hawkbit-artifactdl-defaults.properties index 82d515611..21beef65a 100644 --- a/hawkbit-autoconfigure/src/main/resources/hawkbit-artifactdl-defaults.properties +++ b/hawkbit-autoconfigure/src/main/resources/hawkbit-artifactdl-defaults.properties @@ -14,7 +14,7 @@ hawkbit.artifact.url.protocols.download-http.hostname=localhost hawkbit.artifact.url.protocols.download-http.ip=127.0.0.1 hawkbit.artifact.url.protocols.download-http.protocol=http hawkbit.artifact.url.protocols.download-http.port=8080 -hawkbit.artifact.url.protocols.download-http.supports=DMF,DDI +hawkbit.artifact.url.protocols.download-http.supports=DDI,DMF hawkbit.artifact.url.protocols.download-http.ref={protocolRequest}://{hostnameRequest}:{portRequest}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} hawkbit.artifact.url.protocols.md5sum-http.rel=md5sum-http hawkbit.artifact.url.protocols.md5sum-http.protocol=${hawkbit.artifact.url.protocols.download-http.protocol} diff --git a/hawkbit-core/pom.xml b/hawkbit-core/pom.xml index ff15849da..47ee09287 100644 --- a/hawkbit-core/pom.xml +++ b/hawkbit-core/pom.xml @@ -33,7 +33,6 @@ org.springframework.boot spring-boot-actuator-autoconfigure - compile org.springframework @@ -47,6 +46,20 @@ org.springframework spring-context-support + + org.springframework.security + spring-security-oauth2-core + + + org.springframework.security + spring-security-aspects + + + org.springframework.security + spring-security-web + + true + jakarta.validation @@ -65,6 +78,13 @@ caffeine + + com.fasterxml.jackson.core + jackson-databind + + true + + io.github.classgraph diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/ContextAware.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/ContextAware.java deleted file mode 100644 index c81d267a5..000000000 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/ContextAware.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2023 Bosch.IO 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; - -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; - -import org.eclipse.hawkbit.tenancy.TenantAware; - -/** - * {@link ContextAware} provides means for getting the current context (via {@link #getCurrentContext()}) and then - * to execute a {@link Runnable} or a {@link Function} in the same context using {@link #runInContext(String, Runnable)} - * or {@link #runInContext(String, Function, Object)}. - *

- * This is useful for scheduled background operations like rollouts and auto assignments where they shall - * be processed in the scope of the creator. - */ -public interface ContextAware extends TenantAware { - - /** - * Return the current context encoded as a {@link String}. Depending on the implementation it could, - * for instance, be a serialized context or a reference to such. - * - * @return could be empty if there is nothing to serialize or context aware is not supported. - */ - Optional getCurrentContext(); - - /** - * Wrap a specific execution in a known and pre-serialized context. - * - * @param the type of the input to the function - * @param the type of the result of the function - * @param serializedContext created by {@link #getCurrentContext()}. Must be non-null. - * @param function function to call in the reconstructed context. Must be non-null. - * @param t the argument that will be passed to the function - * @return the function result - */ - R runInContext(String serializedContext, Function function, T t); - - /** - * Wrap a specific execution in a known and pre-serialized context. - * - * @param serializedContext created by {@link #getCurrentContext()}. Must be non-null. - * @param runnable runnable to call in the reconstructed context. Must be non-null. - */ - default void runInContext(String serializedContext, Runnable runnable) { - Objects.requireNonNull(runnable); - runInContext(serializedContext, v -> { - runnable.run(); - return null; - }, null); - } -} \ No newline at end of file diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditContextProvider.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditContextProvider.java new file mode 100644 index 000000000..6e868566a --- /dev/null +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditContextProvider.java @@ -0,0 +1,28 @@ +/** + * 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.audit; + +import java.util.Optional; + +import lombok.NoArgsConstructor; +import org.eclipse.hawkbit.context.AccessContext; + +@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE) +@SuppressWarnings("java:S6548") // java:S6548 - singleton holder ensures static access to spring resources in some places +public class AuditContextProvider { + + public static AuditContext getAuditContext() { + return new AuditContext( + Optional.ofNullable(AccessContext.tenant()).orElse("n/a"), + Optional.ofNullable(AccessContext.actor()).orElse(AccessContext.SYSTEM_ACTOR)); + } + + public record AuditContext(String tenant, String username) {} +} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditLog.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditLog.java similarity index 100% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditLog.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditLog.java diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditLogger.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditLogger.java similarity index 87% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditLogger.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditLogger.java index fbb0c3a02..04b3fda41 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditLogger.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditLogger.java @@ -17,8 +17,6 @@ import org.slf4j.LoggerFactory; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class AuditLogger { - private static final AuditContextProvider AUDIT_CONTEXT_PROVIDER = AuditContextProvider.getInstance(); - public static void info(final String entity, final String message) { logMessage(entity, message, AuditLog.Level.INFO); } @@ -44,13 +42,13 @@ public class AuditLogger { } private static void logMessage(final String entity, final String message, final AuditLog.Level level) { - logMessage(AUDIT_CONTEXT_PROVIDER.getAuditContext().tenant(), AUDIT_CONTEXT_PROVIDER.getAuditContext().username(), entity, message, - level); + final AuditContextProvider.AuditContext auditContext = AuditContextProvider.getAuditContext(); + logMessage(auditContext.tenant(), auditContext.username(), entity, message, level); } private static void logMessage( final String tenant, final String username, final String entity, final String message, final AuditLog.Level level) { - final String logMessage = String.format("[%s] User: %s, Tenant: %s - %s", entity, username, tenant, message); + final String logMessage = String.format("[%s] User: %s, AccessContext: %s - %s", entity, username, tenant, message); final Logger auditLogger = LoggerFactory.getLogger("AUDIT" + (entity != null ? ("." + entity.toUpperCase()) : "")); switch (level) { case INFO: diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditLoggingAspect.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditLoggingAspect.java similarity index 97% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditLoggingAspect.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditLoggingAspect.java index 8a0cbd6a4..958580254 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditLoggingAspect.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/AuditLoggingAspect.java @@ -70,8 +70,8 @@ public class AuditLoggingAspect { * Logs both the request details and the response. */ private void logAudit( - final JoinPoint joinPoint, final AuditLog auditLog, final String resultMessage, final String paramsToLog, - final AuditLog.Level logLevel) { + final JoinPoint joinPoint, + final AuditLog auditLog, final String resultMessage, final String paramsToLog, final AuditLog.Level logLevel) { final String methodName = joinPoint.getSignature().getName(); final String logMessage = String.format( diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/SecurityLogger.java similarity index 58% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/SecurityLogger.java index 44e4ffb62..0366f738b 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/audit/SecurityLogger.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others + * 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 @@ -7,19 +7,18 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.security; +package org.eclipse.hawkbit.audit; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Constants related to security. */ @NoArgsConstructor(access = AccessLevel.PRIVATE) -public final class SecurityConstants { +public final class SecurityLogger { - /** - * Logger prefix used for security logging. - */ - public static final String SECURITY_LOG_PREFIX = "server-security"; + public static final Logger LOGGER = LoggerFactory.getLogger("SERVER.SECURITY"); } \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/Hierarchy.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/Hierarchy.java similarity index 66% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/Hierarchy.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/Hierarchy.java index 8e5db9578..dbbdc1a2f 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/Hierarchy.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/Hierarchy.java @@ -7,10 +7,11 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.im.authentication; +package org.eclipse.hawkbit.auth; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class Hierarchy { @@ -23,4 +24,14 @@ public class Hierarchy { SpPermission.TENANT_CONFIGURATION_HIERARCHY + SpRole.DEFAULT_ROLE_HIERARCHY; // @formatter:on + + private static RoleHierarchy roleHierarchy; + + public static RoleHierarchy getRoleHierarchy() { + return roleHierarchy; + } + + public static void setRoleHierarchy(final RoleHierarchy roleHierarchy) { + Hierarchy.roleHierarchy = roleHierarchy; + } } \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpPermission.java similarity index 84% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpPermission.java index 8abd704d7..6ead58135 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpPermission.java @@ -7,8 +7,9 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.im.authentication; +package org.eclipse.hawkbit.auth; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -16,7 +17,12 @@ import java.util.Set; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.ObjectUtils; import org.springframework.util.function.SingletonSupplier; /** @@ -164,4 +170,27 @@ public final class SpPermission { public static Set getAllTenantAuthorities() { return ALL_TENANT_AUTHORITIES.get(); } + + @SuppressWarnings("java:S3776") // java:S3776 - better in one place for better readability + public static boolean hasPermission(final String permission) { + final SecurityContext context = SecurityContextHolder.getContext(); + if (context != null) { + final Authentication authentication = context.getAuthentication(); + if (authentication != null) { + Collection grantedAuthorities = authentication.getAuthorities(); + final RoleHierarchy roleHierarchy = Hierarchy.getRoleHierarchy(); + if (!ObjectUtils.isEmpty(grantedAuthorities)) { + if (roleHierarchy != null) { + grantedAuthorities = roleHierarchy.getReachableGrantedAuthorities(grantedAuthorities); + } + for (final GrantedAuthority authority : grantedAuthorities) { + if (authority.getAuthority().equals(permission)) { + return true; + } + } + } + } + } + return false; + } } \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpRole.java similarity index 99% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpRole.java index 2b7f75842..c9cf04307 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpRole.java @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.im.authentication; +package org.eclipse.hawkbit.auth; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpringEvalExpressions.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpringEvalExpressions.java similarity index 93% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpringEvalExpressions.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpringEvalExpressions.java index 666dc8b82..01a2a69cb 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpringEvalExpressions.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/SpringEvalExpressions.java @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.im.authentication; +package org.eclipse.hawkbit.auth; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -23,7 +23,7 @@ import org.springframework.security.access.prepost.PreAuthorize; * hasRole([role]) Returns true if the current principal has the specified role. * hasAnyRole([role1,role2]) Returns true if the current principal has any of the supplied roles (given as a comma-separated list of strings) * principal Allows direct access to the principal object representing the current user - * authentication Allows direct access to the current Authentication object obtained from the SecurityContext + * auth Allows direct access to the current Authentication object obtained from the SecurityContext * permitAll Always evaluates to true * denyAll Always evaluates to false * isAnonymous() Returns true if the current principal is an anonymous user diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/StaticAuthenticationProvider.java similarity index 96% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/StaticAuthenticationProvider.java index f6eeed20c..d54accabb 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/auth/StaticAuthenticationProvider.java @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.im.authentication; +package org.eclipse.hawkbit.auth; import java.util.ArrayList; import java.util.Collection; @@ -82,8 +82,10 @@ public class StaticAuthenticationProvider extends DaoAuthenticationProvider { return new FixedInMemoryTenantAwareUserDetailsService(userPrincipals); } + public static final Pattern HAS_SCHEMA = Pattern.compile("^\\{[^{]+}.+$"); + private static String password(final String password) { - return !Pattern.compile("^\\{.+}.*$").matcher(password).matches() ? "{noop}" + password : password; + return !HAS_SCHEMA.matcher(password).matches() ? "{noop}" + password : password; } private static List createAuthorities( diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/context/AccessContext.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/context/AccessContext.java new file mode 100644 index 000000000..63de3830d --- /dev/null +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/context/AccessContext.java @@ -0,0 +1,449 @@ +/** + * 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.context; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AccessLevel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.auth.SpRole; +import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; +import org.eclipse.hawkbit.tenancy.TenantAwareUser; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; + +/** + * A 'static' class providing methods related to access context: + *

    + *
  • read / lookup - find out the current tenant, principal (actor), security context
  • + *
  • switch context - run code as system, as system but scoped for a tenant, with a specific context
  • + *
+ */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@Slf4j +public class AccessContext { + + // Note! There shall be no regular 'system'! + public static final String SYSTEM_ACTOR = "system"; + + /** + * Return the current context encoded as a {@link String}. Depending on the implementation it could, + * for instance, be a serialized context or a reference to such. + * + * @return could be empty if there is nothing to serialize or context aware is not supported. + */ + public static Optional securityContext() { + return Optional.ofNullable(SecurityContextHolder.getContext()).map(AccessContext::serialize); + } + + /** + * Implementation might retrieve the current tenant from a session or thread-local. + * + * @return the current tenant + */ + public static String tenant() { + final SecurityContext context = SecurityContextHolder.getContext(); + if (context.getAuthentication() != null) { + final Object principal = context.getAuthentication().getPrincipal(); + if (context.getAuthentication().getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails) { + return tenantAwareAuthenticationDetails.tenant(); + } else if (principal instanceof TenantAwareUser tenantAwareUser) { + return tenantAwareUser.getTenant(); + } + } + return null; + } + + // Sometimes 'system' need to override the auditor when do create/modify actions in context of a tenant and user. + // Though this could be made using runAsTenantAsUser sometimes (as in transaction) this override is needed + // after runAsTenantAsUser (because it seems that auditor is got in commit time). + // So this thread local variable provides option to override explicitly the auditor. + private static final ThreadLocal ACTOR_OVERRIDE = new ThreadLocal<>(); + + // Return the current actor / auditor / principal name. It could be a user (person), technical user, device, etc. + public static String actor() { + if (ACTOR_OVERRIDE.get() != null) { + return ACTOR_OVERRIDE.get(); + } else { + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (isAuthenticationInvalid(authentication)) { + return null; + } else { + return resolve(authentication); + } + } + } + + /** + * Wrap a specific execution in a known and pre-serialized context. + * + * @param serializedContext created by {@link #securityContext()}. Must be non-null. + * @param runnable runnable to run in the reconstructed context. Must be non-null. + */ + public static void withSecurityContext(final String serializedContext, final Runnable runnable) { + Objects.requireNonNull(runnable); + withSecurityContext(serializedContext, () -> { + runnable.run(); + return null; + }); + } + + /** + * Wrap a specific execution / call in a known and pre-serialized context. + * + * @param the type of the output of the supplier + * @param serializedContext created by {@link #securityContext()}. Must be non-null. + * @param supplier function to call in the reconstructed context. Must be non-null. + * @return the function result + */ + public static T withSecurityContext(final String serializedContext, final Supplier supplier) { + Objects.requireNonNull(serializedContext); + Objects.requireNonNull(supplier); + final SecurityContext securityContext = deserialize(serializedContext); + Objects.requireNonNull(securityContext); + + return withSecurityContext(securityContext, supplier); + } + + public static T withSecurityContext(final SecurityContext securityContext, final Supplier supplier) { + final SecurityContext originalContext = SecurityContextHolder.getContext(); + if (Objects.equals(securityContext, originalContext)) { + return supplier.get(); + } else { + SecurityContextHolder.setContext(securityContext); + try { + return Mdc.withAuthRe(supplier::get); + } finally { + SecurityContextHolder.setContext(originalContext); + } + } + } + + public static void asActor(final String actor, final Runnable runnable) { + asActor(actor, () -> { + runnable.run(); + return null; + }); + } + + public static T asActor(final String actor, final Supplier supplier) { + final String currentAuditor = ACTOR_OVERRIDE.get(); + try { + setActor(actor); + return supplier.get(); + } finally { + setActor(currentAuditor); + } + } + + /** + * Runs a given {@link Runnable} within a system security context, which is permitted to call secured system code. Often the system needs + * to call secured methods by its own without relying on the current security context e.g. if the current security context does not contain + * the necessary permission it's necessary to execute code as system code to execute necessary methods and functionality.
+ * The security context will be switched to the system code and back after the supplier is called.
+ * The system code is executed for a current tenant by using the {@link AccessContext#tenant()}. + * + * @param runnable the runnable to run within the system security context + */ + public static void asSystem(final Runnable runnable) { + asSystemAsTenant(tenant(), () -> { + runnable.run(); + return null; + }); + } + + /** + * Runs a given {@link Supplier} within a system security context, which is permitted to call secured system code. Often the system needs + * to call secured methods by its own without relying on the current security context e.g. if the current security context does not contain + * the necessary permission it's necessary to execute code as system code to execute necessary methods and functionality.
+ * The security context will be switched to the system code and back after the supplier is called.
+ * The system code is executed for a current tenant by using the {@link AccessContext#tenant()}. + * + * @param supplier the supplier to call within the system security context + * @return the return value of the {@link Supplier#get()} method. + */ + public static T asSystem(final Supplier supplier) { + return asSystemAsTenant(tenant(), supplier); + } + + /** + * Runs a given {@link Runnable} within a system security context, which is permitted to call secured system code. Often the system needs + * to call secured methods by its own without relying on the current security context e.g. if the current security context does not contain + * the necessary permission it's necessary to execute code as system code to execute necessary methods and functionality.
+ * The security context will be switched to the system code and back after the runnable is run.
+ * The system code is executed for a specific given tenant by using the {@link AccessContext}. + * + * @param tenant the tenant to act as system code + * @param runnable the runnable to run within the system security context + */ + public static void asSystemAsTenant(final String tenant, final Runnable runnable) { + asSystemAsTenant(tenant, () -> { + runnable.run(); + return null; + }); + } + + /** + * Runs a given {@link Supplier} within a system security context, which is permitted to call secured system code. Often the system needs + * to call secured methods by its own without relying on the current security context e.g. if the current security context does not contain + * the necessary permission it's necessary to execute code as system code to execute necessary methods and functionality.
+ * The security context will be switched to the system code and back after the supplier is run.
+ * The system code is executed for a specific given tenant by using the {@link AccessContext}. + * + * @param tenant the tenant to act as system code + * @param supplier the supplier to call within the system security context + * @return the return value of the {@link Supplier#get()} method. + */ + public static T asSystemAsTenant(final String tenant, final Supplier supplier) { + final SecurityContext currentContext = SecurityContextHolder.getContext(); + try { + log.debug("Entering system code execution"); + final SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new SystemCodeAuthentication(tenant)); + return withSecurityContext(securityContext, supplier); + } finally { + SecurityContextHolder.setContext(currentContext); + log.debug("Leaving system code execution"); + } + } + + private static void setActor(final String currentAuditor) { + if (currentAuditor == null) { + ACTOR_OVERRIDE.remove(); + } else { + ACTOR_OVERRIDE.set(currentAuditor); + } + } + + /** + * @return {@code true} if the current running code is running as system code block. + */ + public static boolean isCurrentThreadSystemCode() { + return SecurityContextHolder.getContext().getAuthentication() instanceof SystemCodeAuthentication; + } + + private static String resolve(final Authentication authentication) { + if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails && tenantAwareDetails.controller()) { + return "CONTROLLER_PLUG_AND_PLAY"; + } + final Object principal = authentication.getPrincipal(); + if (principal instanceof ActorAware actorAware) { + return actorAware.getActor(); + } + if (principal instanceof UserDetails userDetails) { + return userDetails.getUsername(); + } + if (principal instanceof OidcUser oidcUser) { + return oidcUser.getPreferredUsername(); + } + return principal.toString(); + } + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + /** + * Return security context as string (could be just a reference) + * + * @param securityContext the security context + * @return the securityContext as string + */ + @SuppressWarnings("java:S112") // java:S112 - generic method + private static String serialize(final SecurityContext securityContext) { + Objects.requireNonNull(securityContext); + try { + return OBJECT_MAPPER.writeValueAsString(new SecCtxInfo(securityContext)); + } catch (final JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + /** + * Deserialize security context + * + * @param securityContextString string representing the security context + * @return deserialized security context + */ + @SuppressWarnings("java:S112") // java:S112 - generic method + private static SecurityContext deserialize(final String securityContextString) { + Objects.requireNonNull(securityContextString); + final String securityContextTrimmed = securityContextString.trim(); + try { + return OBJECT_MAPPER.readerFor(SecCtxInfo.class). readValue(securityContextTrimmed).toSecurityContext(); + } catch (final JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + private static boolean isAuthenticationInvalid(final Authentication authentication) { + return authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() == null; + } + + public interface ActorAware { + + String getActor(); + } + + // simplified info for the security context keeping just the basic info needed for background execution of + // controller auth is not supported - always is false + // only authenticated user is supported + @NoArgsConstructor + @Data + private static class SecCtxInfo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private String tenant; + // auditor / username (auth principal name) + private String auditor = "n/a"; // default value "n/a" is used only on deserialization if field is missing + @JsonProperty(required = true) + private String[] authorities; + + private SecCtxInfo(final SecurityContext securityContext) { + final Authentication authentication = securityContext.getAuthentication(); + if (!authentication.isAuthenticated()) { + throw new IllegalStateException("Only authenticated context could be serialized"); + } + if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails) { + if (tenantAwareDetails.controller()) { + throw new IllegalStateException("Controller auth context is not supported"); + } + tenant = tenantAwareDetails.tenant(); + } else if (authentication.getPrincipal() instanceof TenantAwareUser tenantAwareUser) { + tenant = tenantAwareUser.getTenant(); + } + + // keep the auditor, ofr audit purposes, + // sets principal to the resolved auditor and then deserialized auth will return it as principal + // since the class is not known to auditor aware - it shall used default - principal as auditor + auditor = resolve(authentication); + authorities = authentication.getAuthorities().stream().map(Object::toString).toArray(String[]::new); + } + + private SecurityContext toSecurityContext() { + final SecurityContext ctx = SecurityContextHolder.createEmptyContext(); + final Object details = tenant == null ? null : new TenantAwareAuthenticationDetails(tenant, false); + final ActorAware principal = () -> auditor; + final Collection grantedAuthorities = + Stream.of(authorities).map(SimpleGrantedAuthority::new).toList(); + ctx.setAuthentication(new Authentication() { + + @Override + public Object getPrincipal() { + return principal; + } + + @Override + public Collection getAuthorities() { + return grantedAuthorities; + } + + @Override + public boolean isAuthenticated() { + return true; + } + + @Override + public Object getDetails() { + return details; + } + + @Override + public Object getCredentials() { + return null; + } + + @Override + public void setAuthenticated(final boolean isAuthenticated) throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } + + @Override + public String getName() { + return auditor; + } + }); + return ctx; + } + } + + /** + * An implementation of the Spring's {@link Authentication} object which is used within a system security code block and + * wraps the original auth object. The wrapped object contains the necessary {@link SpRole#SYSTEM_ROLE} + * which is allowed to execute all secured methods. + */ + static final class SystemCodeAuthentication implements Authentication { + + @Serial + private static final long serialVersionUID = 1L; + + private static final List AUTHORITIES = List.of(new SimpleGrantedAuthority(SpRole.SYSTEM_ROLE)); + + private final TenantAwareAuthenticationDetails details; + private final TenantAwareUser principal; + + private SystemCodeAuthentication(final String tenant) { + details = new TenantAwareAuthenticationDetails(tenant, false); + principal = new TenantAwareUser(SYSTEM_ACTOR, SYSTEM_ACTOR, AUTHORITIES, tenant); + } + + @Override + public String getName() { + return null; + } + + @Override + public Collection getAuthorities() { + return AUTHORITIES; + } + + @Override + public Object getCredentials() { + return null; + } + + @Override + public Object getDetails() { + return details; + } + + @Override + public Object getPrincipal() { + return principal; + } + + @Override + public boolean isAuthenticated() { + return true; + } + + @Override + public void setAuthenticated(final boolean isAuthenticated) { + throw new UnsupportedOperationException(); + } + } +} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/context/Mdc.java similarity index 59% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/context/Mdc.java index aca000d0e..711473e19 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/context/Mdc.java @@ -7,10 +7,11 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.security; +package org.eclipse.hawkbit.context; import java.io.IOException; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.Callable; import jakarta.servlet.FilterChain; @@ -22,8 +23,6 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; import org.slf4j.MDC; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -31,42 +30,34 @@ import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.web.filter.OncePerRequestFilter; @NoArgsConstructor(access = AccessLevel.PRIVATE) -// java:S6548 - singleton holder ensures static access to spring resources in some places // java:S112 - it is generic class so a generic exception is fine -@SuppressWarnings({ "java:S6548", "java:S112" }) -public class MdcHandler { +@SuppressWarnings("java:S112") +public class Mdc { public static final String MDC_KEY_TENANT = "tenant"; - public static final String MDC_KEY_USER = "user"; + // in the MDC the default actor key is "user" + public static final String MDC_KEY_ACTOR = System.getProperty( + "hawkbit.mdc.actor.key", // first by priority: system property + Optional.ofNullable(System.getenv("HAWKBIT_MDC_ACTOR_KEY")) // second by priority: environment variable + .orElse("user")); // default if not set - private static final MdcHandler SINGLETON = new MdcHandler(); + private static boolean enabled = true; - @Value("${hawkbit.logging.mdchandler.enabled:true}") - private boolean mdcEnabled; - private SpringSecurityAuditorAware springSecurityAuditorAware = new SpringSecurityAuditorAware(); - - /** - * @return The holder singleton instance. - */ - public static MdcHandler getInstance() { - return SINGLETON; - } - - @Autowired(required = false) // spring setter injection - public void setSpringSecurityAuditorAware(final SpringSecurityAuditorAware springSecurityAuditorAware) { - this.springSecurityAuditorAware = springSecurityAuditorAware; + // hook to disable (otherwise enabled by default) MDC context management + public static void setEnabled(final boolean enabled) { + Mdc.enabled = enabled; } /** - * Executes callable and returns the result. If MDC is enabled, it sets the tenant and / or user from the authentication in the MDC context. + * Executes callable and returns the result. If MDC is enabled, it sets the tenant and / or actor from the auth in the MDC context. * * @param the return type * @param callable the callable to execute * @return the result * @throws Exception if thrown by the callable */ - public T callWithAuth(final Callable callable) throws Exception { - if (!mdcEnabled) { + public static T withAuth(final Callable callable) throws Exception { + if (!enabled) { return callable.call(); } @@ -82,25 +73,24 @@ public class MdcHandler { tenant = null; } - final String user = springSecurityAuditorAware - .getCurrentAuditor() - .filter(username -> !username.equals(SecurityContextTenantAware.SYSTEM_USER)) // null and system are the same - system user + final String actor = Optional.ofNullable(AccessContext.actor()) + .filter(ctxActor -> !ctxActor.equals(AccessContext.SYSTEM_ACTOR)) // null and system are the same - system actor .orElse(null); - return callWithTenantAndUser0(callable, tenant, user); + return asTenantAsActor0(tenant, actor, callable); } /** - * Executes callable and returns the result. If MDC is enabled, it sets the tenant and / or user from the authentication in the MDC context. - * Calls the {@link #callWithAuth(Callable)} method and wraps any catchable exception into a {@link RuntimeException}. + * Executes callable and returns the result. If MDC is enabled, it sets the tenant and / or actor from the auth in the MDC context. + * Calls the {@link #withAuth(Callable)} method and wraps any catchable exception into a {@link RuntimeException}. * * @param the return type * @param callable the callable to execute * @return the result */ - public T callWithAuthRE(final Callable callable) { + public static T withAuthRe(final Callable callable) { try { - return callWithAuth(callable); + return withAuth(callable); } catch (final RuntimeException re) { throw re; } catch (final Exception e) { @@ -109,35 +99,35 @@ public class MdcHandler { } /** - * Executes callable and returns the result. If MDC is enabled, it sets the tenant and / or user in the MDC context. + * Executes callable and returns the result. If MDC is enabled, it sets the tenant and / or actor in the MDC context. * * @param the return type - * @param callable the callable to execute * @param tenant the tenant to set in the MDC context - * @param user the user to set in the MDC context + * @param actor the actor to set in the MDC context + * @param callable the callable to execute * @return the result */ - public T callWithTenantAndUser(final Callable callable, final String tenant, final String user) throws Exception { - if (!mdcEnabled) { + public static T asTenantAsActor(final String tenant, final String actor, final Callable callable) throws Exception { + if (!enabled) { return callable.call(); } - return callWithTenantAndUser0(callable, tenant, user); + return asTenantAsActor0(tenant, actor, callable); } /** - * Executes callable and returns the result. If MDC is enabled, it sets the tenant and / or user from the authentication in the MDC context. - * Calls the {@link #callWithTenantAndUser(Callable, String, String)} method and wraps any catchable exception into a {@link RuntimeException}. + * Executes callable and returns the result. If MDC is enabled, it sets the tenant and / or actor from the auth in the MDC context. + * Calls the {@link #asTenantAsActor(String, String, Callable)} method and wraps any catchable exception into a {@link RuntimeException}. * * @param the return type - * @param callable the callable to execute * @param tenant the tenant to set in the MDC context - * @param user the user to set in the MDC context + * @param actor the actor to set in the MDC context + * @param callable the callable to execute * @return the result */ - public T callWithTenantAndUserRE(final Callable callable, final String tenant, final String user) { + public static T asTenantAsActorRe(final String tenant, final String actor, final Callable callable) { try { - return callWithTenantAndUser(callable, tenant, user); + return asTenantAsActor(tenant, actor, callable); } catch (final RuntimeException re) { throw re; } catch (final Exception e) { @@ -145,30 +135,30 @@ public class MdcHandler { } } - private static T callWithTenantAndUser0(final Callable callable, final String tenant, final String user) throws Exception { + private static T asTenantAsActor0(final String tenant, final String actor, final Callable callable) throws Exception { final String currentTenant = MDC.get(MDC_KEY_TENANT); if (Objects.equals(currentTenant, tenant)) { - return callWithUser(callable, user); + return asActor(callable, actor); } else { put(MDC_KEY_TENANT, tenant); try { - return callWithUser(callable, user); + return asActor(callable, actor); } finally { put(MDC_KEY_TENANT, currentTenant); } } } - private static T callWithUser(final Callable callable, final String user) throws Exception { - final String currentUser = MDC.get(MDC_KEY_USER); - if (Objects.equals(currentUser, user)) { + private static T asActor(final Callable callable, final String actor) throws Exception { + final String currentActor = MDC.get(MDC_KEY_ACTOR); + if (Objects.equals(currentActor, actor)) { return callable.call(); } else { - put(MDC_KEY_USER, user); + put(MDC_KEY_ACTOR, actor); try { return callable.call(); } finally { - put(MDC_KEY_USER, currentUser); + put(MDC_KEY_ACTOR, currentActor); } } } @@ -187,14 +177,12 @@ public class MdcHandler { public static void addMdcFilter(final HttpSecurity httpSecurity) { httpSecurity.addFilterBefore(new OncePerRequestFilter() { - private final MdcHandler mdcFilter = MdcHandler.getInstance(); - @Override protected void doFilterInternal( final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException { try { - mdcFilter.callWithAuth(() -> { + Mdc.withAuth(() -> { filterChain.doFilter(request, response); return null; }); diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java index ddc08ca89..a79c6e822 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java @@ -12,7 +12,7 @@ package org.eclipse.hawkbit.exception; import lombok.Getter; /** - * Define the Error codes for Error handling + * Define the error codes for error handling */ @Getter public enum SpServerError { @@ -182,9 +182,6 @@ public enum SpServerError { private final String key; private final String message; - /** - * Repository side Error codes - */ SpServerError(final String key, final String message) { this.key = key; this.message = message; diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java similarity index 96% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java index 5286f1cff..cddf3e4de 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java @@ -43,11 +43,11 @@ public class HawkbitSecurityProperties { */ private List httpFirewallIgnoredPaths; /** - * Basic authentication realm, see https://tools.ietf.org/html/rfc2617#page-3 . + * Basic auth realm, see https://tools.ietf.org/html/rfc2617#page-3 . */ private String basicRealm = "hawkBit"; /** - * If to allow http authentication when there is OAuth2 authentication enabled. + * If to allow http auth when there is OAuth2 auth enabled. */ private boolean allowHttpBasicOnOAuthEnabled = false; @@ -103,7 +103,7 @@ public class HawkbitSecurityProperties { public static final String X_FORWARDED_FOR = "X-Forwarded-For"; /** - * Blacklisted client (IP addresses) for for DDI and Management API. + * Blacklisted client (IP addresses) for DDI and Management API. */ private String blacklist = ""; /** @@ -117,7 +117,7 @@ public class HawkbitSecurityProperties { } /** - * Denial of service protection related properties. + * Denial-of-service (DoS) protection related properties. */ @Data public static class Dos { diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/DefaultTenantConfiguration.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/DefaultTenantConfiguration.java index 68f3707cf..aa0296887 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/DefaultTenantConfiguration.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/DefaultTenantConfiguration.java @@ -18,6 +18,7 @@ import io.micrometer.common.KeyValues; import io.micrometer.core.instrument.Tag; import io.micrometer.observation.ObservationRegistry; import lombok.NonNull; +import org.eclipse.hawkbit.context.AccessContext; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration; @@ -44,12 +45,6 @@ public class DefaultTenantConfiguration { public static final String TENANT_TAG = "tenant"; - @Bean - @ConditionalOnMissingBean - TenantAware.TenantResolver tenantResolver() { - return new TenantAware.DefaultTenantResolver(); - } - @Bean @ConditionalOnMissingBean TenantAwareCacheManager cacheManager() { @@ -62,12 +57,12 @@ public class DefaultTenantConfiguration { @ConditionalOnProperty(name = "hawkbit.metrics.tenancy.web.enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass(name = { "org.springframework.web.servlet.DispatcherServlet", "io.micrometer.observation.Observation" }) - @ConditionalOnBean({ ObservationRegistry.class, TenantAware.TenantResolver.class }) + @ConditionalOnBean(ObservationRegistry.class) public static class WebConfig { @Bean @Primary - public DefaultServerRequestObservationConvention serverRequestObservationConvention(final TenantAware.TenantResolver tenantResolver) { + public DefaultServerRequestObservationConvention serverRequestObservationConvention() { return new DefaultServerRequestObservationConvention() { @NonNull @@ -78,7 +73,7 @@ public class DefaultTenantConfiguration { } private KeyValue tenant() { - return KeyValue.of(TENANT_TAG, Optional.ofNullable(tenantResolver.resolveTenant()).orElse("n/a")); + return KeyValue.of(TENANT_TAG, Optional.ofNullable(AccessContext.tenant()).orElse("n/a")); } }; } @@ -104,17 +99,16 @@ public class DefaultTenantConfiguration { @ConditionalOnClass(name = { "io.micrometer.core.instrument.Tag", "org.springframework.data.repository.core.support.RepositoryMethodInvocationListener" }) - @ConditionalOnBean(TenantAware.TenantResolver.class) public static class RepositoryConfig { @Bean - public RepositoryTagsProvider repositoryTagsProvider(final TenantAware.TenantResolver tenantResolver) { + public RepositoryTagsProvider repositoryTagsProvider() { return new DefaultRepositoryTagsProvider() { @Override public Iterable repositoryTags(final RepositoryMethodInvocationListener.RepositoryMethodInvocation invocation) { final Iterable defaultTags = super.repositoryTags(invocation); - final String tenant = Optional.ofNullable(tenantResolver.resolveTenant()).orElse("n/a"); + final String tenant = Optional.ofNullable(AccessContext.tenant()).orElse("n/a"); return () -> { final Iterator defaultTagsIterator = defaultTags.iterator(); return new Iterator<>() { 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 deleted file mode 100644 index 48ac0b1fb..000000000 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAware.java +++ /dev/null @@ -1,79 +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.tenancy; - -import java.util.concurrent.Callable; - -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; - -/** - * Interface for components that are aware of the application's current tenant. - */ -public interface TenantAware { - - /** - * Implementation might retrieve the current tenant from a session or thread-local. - * - * @return the current tenant - */ - String getCurrentTenant(); - - /** - * @return the username of the currently logged-in user - */ - String getCurrentUsername(); - - /** - * 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 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, Callable callable); - - /** - * Gives the possibility to run a certain code under a specific given {@code tenant} and {@code username}. - * 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 - */ - void runAsTenantAsUser(String tenant, String username, Runnable runnable); - - /** - * Resolves the tenant from the current context. - */ - interface TenantResolver { - - String resolveTenant(); - } - - class DefaultTenantResolver implements TenantResolver { - - @Override - public String resolveTenant() { - final SecurityContext context = SecurityContextHolder.getContext(); - if (context.getAuthentication() != null) { - final Object principal = context.getAuthentication().getPrincipal(); - if (context.getAuthentication().getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails) { - return tenantAwareAuthenticationDetails.tenant(); - } else if (principal instanceof TenantAwareUser tenantAwareUser) { - return tenantAwareUser.getTenant(); - } - } - return null; - } - } -} \ No newline at end of file diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAwareAuthenticationDetails.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAwareAuthenticationDetails.java index 3acc7b42f..68b435f60 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAwareAuthenticationDetails.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAwareAuthenticationDetails.java @@ -15,8 +15,8 @@ import java.io.Serializable; import org.springframework.security.authentication.AbstractAuthenticationToken; /** - * An authentication details object {@link AbstractAuthenticationToken#getDetails()} which is stored in the - * spring security authentication token details to transport the principal and tenant in the security context session. + * An auth details object {@link AbstractAuthenticationToken#getDetails()} which is stored in the + * spring security auth token details to transport the principal and tenant in the security context session. */ public record TenantAwareAuthenticationDetails(String tenant, boolean controller) implements Serializable { diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAwareCacheManager.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAwareCacheManager.java index 009d29cb8..94af1b862 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAwareCacheManager.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/TenantAwareCacheManager.java @@ -22,7 +22,7 @@ import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.Value; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.tenancy.TenantAware.TenantResolver; +import org.eclipse.hawkbit.context.AccessContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; @@ -34,7 +34,7 @@ import org.springframework.lang.Nullable; /** * A spring Cache Manager that handles the multi tenancy. *
    - *
  • If a tenant is resolved by the {@link TenantResolver}, a dedicated cache manager for that tenant is used/created.
  • + *
  • If a tenant is resolved by the {@link AccessContext}, a dedicated cache manager for that tenant is used/created.
  • *
  • If no tenant is resolved, a global cache manager is used.
  • *
*/ @@ -50,7 +50,6 @@ public class TenantAwareCacheManager implements CacheManager { private CacheManager globalCacheManager; private final Map tenant2CacheManager = new ConcurrentHashMap<>(); - private TenantResolver resolver; private Environment env; // default caffeine cache spec - see com.github.benmanes.caffeine.cache.CaffeineSpec javadoc for format details @@ -61,8 +60,7 @@ public class TenantAwareCacheManager implements CacheManager { } @Autowired - public void init(final TenantResolver resolver, final Environment env) { - this.resolver = resolver; + public void init(final Environment env) { this.env = env; defaultSpec = env.resolvePlaceholders("${" + CONFIG_PREFIX + CONFIG_SPEC + ":expireAfterWrite=${hawkbit.cache.ttl:10s}}"); globalCacheManager = new TenantCacheManager(null); @@ -71,7 +69,7 @@ public class TenantAwareCacheManager implements CacheManager { @NonNull @Override public Cache getCache(@NonNull final String name) { - final Cache cache = Optional.ofNullable(resolver.resolveTenant()) + final Cache cache = Optional.ofNullable(AccessContext.tenant()) .map(currentTenant -> tenant2CacheManager.computeIfAbsent(currentTenant, TenantCacheManager::new)) .orElse(globalCacheManager) .getCache(name); @@ -81,7 +79,7 @@ public class TenantAwareCacheManager implements CacheManager { @NonNull @Override public Collection getCacheNames() { - final String currentTenant = resolver.resolveTenant(); + final String currentTenant = AccessContext.tenant(); if (currentTenant == null) { return globalCacheManager.getCacheNames(); } else { diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/UserAuthoritiesResolver.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/UserAuthoritiesResolver.java deleted file mode 100644 index 3b6a4e382..000000000 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/UserAuthoritiesResolver.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2020 Bosch.IO 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.tenancy; - -import java.util.Collection; - -/** - * The service responsible for making the lookup for user authorities/roles based on his tenant and username - */ -@FunctionalInterface -public interface UserAuthoritiesResolver { - - /** - * User authorities/roles lookup based on the username and the tenant context - * - * @param username The username of the user - * @return a {@link Collection} of authorities/roles for this user - */ - Collection getUserAuthorities(String username); -} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/utils/IpUtil.java similarity index 99% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/utils/IpUtil.java index bb9a52102..8a557ff8b 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/utils/IpUtil.java @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.util; +package org.eclipse.hawkbit.utils; import java.lang.annotation.Target; import java.net.URI; diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SecurityContextSerializerTest.java b/hawkbit-core/src/test/java/org/eclipse/hawkbit/context/SecurityContextSerializerTest.java similarity index 61% rename from hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SecurityContextSerializerTest.java rename to hawkbit-core/src/test/java/org/eclipse/hawkbit/context/SecurityContextSerializerTest.java index d9d250582..70f6c35ef 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SecurityContextSerializerTest.java +++ b/hawkbit-core/src/test/java/org/eclipse/hawkbit/context/SecurityContextSerializerTest.java @@ -7,16 +7,16 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.security; +package org.eclipse.hawkbit.context; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.security.SecurityContextSerializer.JSON_SERIALIZATION; +import static org.eclipse.hawkbit.context.AccessContext.withSecurityContext; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; import org.junit.jupiter.api.Test; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -39,11 +39,12 @@ class SecurityContextSerializerTest { userPassAuthentication.setDetails(details); securityContext.setAuthentication(userPassAuthentication); - final String serialized = JSON_SERIALIZATION.serialize(securityContext); - final SecurityContext deserialized = JSON_SERIALIZATION.deserialize(serialized); + final String serialized = serialize(securityContext); + final SecurityContext deserialized = deserialize(serialized); final Authentication authentication = deserialized.getAuthentication(); - assertThat(SpringSecurityAuditorAware.resolveAuditor(authentication)).hasToString("user"); - assertThat(authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet())).isEqualTo(AUTHORITIES); + assertThat(resolve(authentication)).hasToString("user"); + assertThat(authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet())) + .isEqualTo(AUTHORITIES); assertThat(authentication.isAuthenticated()).isTrue(); assertThat(authentication.getDetails()).isEqualTo(details); } @@ -53,34 +54,16 @@ class SecurityContextSerializerTest { final SecurityContext securityContext = SecurityContextHolder.getContext(); final UsernamePasswordAuthenticationToken userPassAuthentication = new UsernamePasswordAuthenticationToken( "FirstName.FamilyName@domain1.domain0.com", - Map.of("should not be in" + bigString(10_000),"the output" + bigString(15_000)), + Map.of("should not be in" + bigString(10_000), "the output" + bigString(15_000)), AUTHORITIES.stream().map(SimpleGrantedAuthority::new).toList()); final TenantAwareAuthenticationDetails details = new TenantAwareAuthenticationDetails("my_test_enant", false); userPassAuthentication.setDetails(details); securityContext.setAuthentication(userPassAuthentication); - final String serialized = JSON_SERIALIZATION.serialize(securityContext); + final String serialized = serialize(securityContext); assertThat(serialized).hasSizeLessThan(4096); // ensure that it is not too big } - @Test - void testUsername() { - final SecurityContext securityContext = SecurityContextHolder.getContext(); - final UsernamePasswordAuthenticationToken userPassAuthentication = new UsernamePasswordAuthenticationToken( - "user", null, AUTHORITIES.stream().map(SimpleGrantedAuthority::new).toList()); - final TenantAwareAuthenticationDetails details = new TenantAwareAuthenticationDetails("my_tenant", false); - userPassAuthentication.setDetails(details); - securityContext.setAuthentication(userPassAuthentication); - - final String serialized = JSON_SERIALIZATION.serialize(securityContext).replace("auditor", "username"); - final SecurityContext deserialized = JSON_SERIALIZATION.deserialize(serialized); - final Authentication authentication = deserialized.getAuthentication(); - assertThat(SpringSecurityAuditorAware.resolveAuditor(authentication)).hasToString("user"); - assertThat(authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet())).isEqualTo(AUTHORITIES); - assertThat(authentication.isAuthenticated()).isTrue(); - assertThat(authentication.getDetails()).isEqualTo(details); - } - private static String bigString(final int length) { final StringBuilder sb = new StringBuilder(length); for (int i = 0; i < length; i++) { @@ -88,4 +71,18 @@ class SecurityContextSerializerTest { } return sb.toString(); } + + private static String serialize(final SecurityContext securityContext) { + return withSecurityContext(securityContext, () -> AccessContext.securityContext().orElseThrow()); + } + + private static SecurityContext deserialize(final String serialized) { + return withSecurityContext(serialized, SecurityContextHolder::getContext); + } + + private static String resolve(final Authentication authentication) { + final SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(authentication); + return withSecurityContext(securityContext, AccessContext::actor); + } } \ No newline at end of file diff --git a/hawkbit-core/src/test/java/org/eclipse/hawkbit/context/SystemSecurityContextTest.java b/hawkbit-core/src/test/java/org/eclipse/hawkbit/context/SystemSecurityContextTest.java new file mode 100644 index 000000000..47a3facf0 --- /dev/null +++ b/hawkbit-core/src/test/java/org/eclipse/hawkbit/context/SystemSecurityContextTest.java @@ -0,0 +1,69 @@ +/** + * 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.context; + +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; + +import java.util.List; + +import org.assertj.core.api.Assertions; +import org.eclipse.hawkbit.auth.SpRole; +import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; +import org.junit.jupiter.api.Test; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +class SystemSecurityContextTest { + + @Test + void test() { + final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("test", "pass", List.of(new SimpleGrantedAuthority("anonymous"))); + auth.setDetails("string details"); + test(auth); + } + + @Test + void testWithNullPrincipal() { + final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(null, "pass", List.of(new SimpleGrantedAuthority("anonymous"))); + auth.setDetails("string details"); + test(auth); + } + + @Test + void testWithNullCredentials() { + final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("test", null, List.of(new SimpleGrantedAuthority("anonymous"))); + auth.setDetails("string details"); + test(auth); + } + + @Test + void testWitAllNull() { + final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(null, null, List.of(new SimpleGrantedAuthority("anonymous"))); + auth.setDetails(null); + test(auth); + } + + private static void test(final UsernamePasswordAuthenticationToken auth) { + final SecurityContext sc = SecurityContextHolder.createEmptyContext(); + sc.setAuthentication(auth); + SecurityContextHolder.setContext(sc); + asSystemAsTenant("tenant", () -> { + final Authentication currentAuth = SecurityContextHolder.getContext().getAuthentication(); + Assertions.assertThat(currentAuth.getClass().getSimpleName()).isEqualTo("SystemCodeAuthentication"); + Assertions.assertThat(currentAuth.getCredentials()).isNull(); + Assertions.assertThat(currentAuth.getAuthorities()).isEqualTo(List.of(new SimpleGrantedAuthority(SpRole.SYSTEM_ROLE))); + Assertions.assertThat(currentAuth.getDetails()).isEqualTo(new TenantAwareAuthenticationDetails("tenant", false)); + }); + SecurityContextHolder.clearContext(); + } +} \ No newline at end of file diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java b/hawkbit-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java similarity index 95% rename from hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java rename to hawkbit-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java index eacceb249..147667d3d 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java +++ b/hawkbit-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Collection; +import org.eclipse.hawkbit.auth.SpPermission; import org.junit.jupiter.api.Test; /** diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java b/hawkbit-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java similarity index 99% rename from hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java rename to hawkbit-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java index c035bd1bf..4a549a945 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java +++ b/hawkbit-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java @@ -21,17 +21,18 @@ import jakarta.servlet.http.HttpServletRequest; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.security.HawkbitSecurityProperties.Clients; +import org.eclipse.hawkbit.utils.IpUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -@ExtendWith(MockitoExtension.class) /** * Feature: Unit Tests - Security
* Story: IP Util Test */ +@ExtendWith(MockitoExtension.class) class IpUtilTest { private static final String X_FORWARDED_FOR = HawkbitSecurityProperties.Clients.X_FORWARDED_FOR; diff --git a/hawkbit-ddi/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java b/hawkbit-ddi/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java index 1daf9306f..f0aa521a5 100644 --- a/hawkbit-ddi/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java +++ b/hawkbit-ddi/hawkbit-ddi-api/src/main/java/org/eclipse/hawkbit/ddi/rest/api/DdiRootControllerRestApi.java @@ -68,7 +68,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -107,7 +107,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to " + "be changed (i.e. read-only) or data volume restriction applies.", @@ -143,7 +143,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be" + " changed (i.e. read-only) or data volume restriction applies.", @@ -181,7 +181,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -244,7 +244,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -289,7 +289,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -336,7 +336,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -377,7 +377,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -414,7 +414,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -474,7 +474,7 @@ public interface DdiRootControllerRestApi { """), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -516,7 +516,7 @@ public interface DdiRootControllerRestApi { """), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -565,7 +565,7 @@ public interface DdiRootControllerRestApi { "the action awaiting confirmation in the same format as for the deploymentBase operation."), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -607,7 +607,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -658,7 +658,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -701,7 +701,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -744,7 +744,7 @@ public interface DdiRootControllerRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) " + "or data volume restriction applies.", diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java b/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java index 4938ee76f..c171f10d6 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DataConversionHelper.java @@ -16,6 +16,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver; import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver.DownloadDescriptor; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.json.model.DdiArtifact; import org.eclipse.hawkbit.ddi.json.model.DdiArtifactHash; import org.eclipse.hawkbit.ddi.json.model.DdiAutoConfirmationState; @@ -34,7 +35,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TenantMetaData; import org.eclipse.hawkbit.rest.json.model.ResponseList; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.hateoas.Link; import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; import org.springframework.http.HttpRequest; @@ -47,25 +47,24 @@ import org.springframework.util.CollectionUtils; public final class DataConversionHelper { public static DdiConfirmationBase createConfirmationBase( - final Target target, final Action activeAction, - final DdiAutoConfirmationState autoConfirmationState, final TenantAware tenantAware) { + final Target target, final Action activeAction, final DdiAutoConfirmationState autoConfirmationState) { final String controllerId = target.getControllerId(); final DdiConfirmationBase confirmationBase = new DdiConfirmationBase(autoConfirmationState); if (autoConfirmationState.isActive()) { confirmationBase.add(WebMvcLinkBuilder - .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) - .deactivateAutoConfirmation(tenantAware.getCurrentTenant(), controllerId)) + .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, AccessContext.tenant()) + .deactivateAutoConfirmation(AccessContext.tenant(), controllerId)) .withRel(DdiRestConstants.AUTO_CONFIRM_DEACTIVATE).expand()); } else { confirmationBase.add(WebMvcLinkBuilder - .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) - .activateAutoConfirmation(tenantAware.getCurrentTenant(), controllerId, null)) + .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, AccessContext.tenant()) + .activateAutoConfirmation(AccessContext.tenant(), controllerId, null)) .withRel(DdiRestConstants.AUTO_CONFIRM_ACTIVATE).expand()); } if (activeAction != null && activeAction.isWaitingConfirmation()) { confirmationBase.add(WebMvcLinkBuilder - .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) - .getConfirmationBaseAction(tenantAware.getCurrentTenant(), controllerId, + .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, AccessContext.tenant()) + .getConfirmationBaseAction(AccessContext.tenant(), controllerId, activeAction.getId(), calculateEtag(activeAction), null)) .withRel(DdiRestConstants.CONFIRMATION_BASE).expand()); } @@ -75,22 +74,22 @@ public final class DataConversionHelper { public static DdiControllerBase fromTarget( final Target target, final Action installedAction, - final Action activeAction, final String defaultControllerPollTime, final TenantAware tenantAware) { + final Action activeAction, final String defaultControllerPollTime) { final DdiControllerBase result = new DdiControllerBase( new DdiConfig(new DdiPolling(defaultControllerPollTime))); if (activeAction != null) { if (activeAction.isWaitingConfirmation()) { result.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder - .methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) - .getConfirmationBaseAction(tenantAware.getCurrentTenant(), target.getControllerId(), + .methodOn(DdiRootController.class, AccessContext.tenant()) + .getConfirmationBaseAction(AccessContext.tenant(), target.getControllerId(), activeAction.getId(), calculateEtag(activeAction), null)) .withRel(DdiRestConstants.CONFIRMATION_BASE).expand()); } else if (activeAction.isCancelingOrCanceled()) { result.add(WebMvcLinkBuilder - .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) - .getControllerCancelAction(tenantAware.getCurrentTenant(), target.getControllerId(), + .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, AccessContext.tenant()) + .getControllerCancelAction(AccessContext.tenant(), target.getControllerId(), activeAction.getId())) .withRel(DdiRestConstants.CANCEL_ACTION).expand()); } else { @@ -98,9 +97,9 @@ public final class DataConversionHelper { // have changed from 'soft' to 'forced' type, and we need to change the payload of the // response because of eTags. result.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder - .methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) + .methodOn(DdiRootController.class, AccessContext.tenant()) .getControllerDeploymentBaseAction( - tenantAware.getCurrentTenant(), target.getControllerId(), + AccessContext.tenant(), target.getControllerId(), activeAction.getId(), calculateEtag(activeAction), null)) .withRel(DdiRestConstants.DEPLOYMENT_BASE_ACTION).expand()); } @@ -109,8 +108,8 @@ public final class DataConversionHelper { if (installedAction != null && !installedAction.isActive()) { result.add( WebMvcLinkBuilder - .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) - .getControllerInstalledAction(tenantAware.getCurrentTenant(), + .linkTo(WebMvcLinkBuilder.methodOn(DdiRootController.class, AccessContext.tenant()) + .getControllerInstalledAction(AccessContext.tenant(), target.getControllerId(), installedAction.getId(), null)) .withRel(DdiRestConstants.INSTALLED_BASE_ACTION).expand()); } @@ -118,9 +117,9 @@ public final class DataConversionHelper { if (target.isRequestControllerAttributes()) { result.add(WebMvcLinkBuilder .linkTo(WebMvcLinkBuilder - .methodOn(DdiRootController.class, tenantAware.getCurrentTenant()) + .methodOn(DdiRootController.class, AccessContext.tenant()) // doesn't really call the putConfigData with null, just create the link - .putConfigData(null, tenantAware.getCurrentTenant(), target.getControllerId())) + .putConfigData(null, AccessContext.tenant(), target.getControllerId())) .withRel(DdiRestConstants.CONFIG_DATA_ACTION).expand()); } diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java b/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java index b01a28d99..72c196946 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.artifact.model.ArtifactStream; import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver; import org.eclipse.hawkbit.audit.AuditLog; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback; import org.eclipse.hawkbit.ddi.json.model.DdiActionHistory; import org.eclipse.hawkbit.ddi.json.model.DdiActivateAutoConfirmation; @@ -68,8 +69,7 @@ import org.eclipse.hawkbit.rest.util.FileStreamingUtil; import org.eclipse.hawkbit.rest.util.HttpUtil; import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.utils.IpUtil; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Scope; import org.springframework.http.HttpHeaders; @@ -102,7 +102,6 @@ public class DdiRootController implements DdiRootControllerRestApi { private final SystemManagement systemManagement; private final ApplicationEventPublisher eventPublisher; private final HawkbitSecurityProperties securityProperties; - private final TenantAware tenantAware; @SuppressWarnings("java:S107") public DdiRootController( @@ -110,7 +109,7 @@ public class DdiRootController implements DdiRootControllerRestApi { final ArtifactManagement artifactManagement, final ArtifactUrlResolver artifactUrlHandler, final SystemManagement systemManagement, final ApplicationEventPublisher eventPublisher, - final HawkbitSecurityProperties securityProperties, final TenantAware tenantAware) { + final HawkbitSecurityProperties securityProperties) { this.controllerManagement = controllerManagement; this.confirmationManagement = confirmationManagement; this.artifactManagement = artifactManagement; @@ -118,7 +117,6 @@ public class DdiRootController implements DdiRootControllerRestApi { this.systemManagement = systemManagement; this.eventPublisher = eventPublisher; this.securityProperties = securityProperties; - this.tenantAware = tenantAware; } @Override @@ -155,7 +153,7 @@ public class DdiRootController implements DdiRootControllerRestApi { installedAction, activeAction, activeAction == null ? controllerManagement.getPollingTime(target) - : controllerManagement.getPollingTimeForAction(target, activeAction), tenantAware), + : controllerManagement.getPollingTimeForAction(target, activeAction)), HttpStatus.OK); } @@ -190,7 +188,7 @@ public class DdiRootController implements DdiRootControllerRestApi { (length, shippedSinceLastEvent, total) -> { if (actionStatus != null) { eventPublisher.publishEvent(new DownloadProgressEvent( - tenantAware.getCurrentTenant(), actionStatus.getId(), shippedSinceLastEvent)); + AccessContext.tenant(), actionStatus.getId(), shippedSinceLastEvent)); } }); } @@ -352,14 +350,13 @@ public class DdiRootController implements DdiRootControllerRestApi { @Override public ResponseEntity getConfirmationBase(final String tenant, final String controllerId) { log.debug("getConfirmationBase is called [controllerId={}].", controllerId); - final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, IpUtil - .getClientIpFromRequest(RequestResponseContextHolder.getHttpServletRequest(), securityProperties)); + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist( + controllerId, IpUtil.getClientIpFromRequest(RequestResponseContextHolder.getHttpServletRequest(), securityProperties)); final Action activeAction = controllerManagement.findActiveActionWithHighestWeight(controllerId).orElse(null); final DdiAutoConfirmationState autoConfirmationState = getAutoConfirmationState(controllerId); - final DdiConfirmationBase confirmationBase = DataConversionHelper.createConfirmationBase( - target, activeAction, autoConfirmationState, tenantAware); + final DdiConfirmationBase confirmationBase = DataConversionHelper.createConfirmationBase(target, activeAction, autoConfirmationState); return new ResponseEntity<>(confirmationBase, HttpStatus.OK); } diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/AbstractDDiApiIntegrationTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/AbstractDDiApiIntegrationTest.java index 6dc8545c0..aa046bb56 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/AbstractDDiApiIntegrationTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/AbstractDDiApiIntegrationTest.java @@ -32,6 +32,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.cbor.CBORFactory; import com.fasterxml.jackson.dataformat.cbor.CBORGenerator; import com.fasterxml.jackson.dataformat.cbor.CBORParser; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback; import org.eclipse.hawkbit.ddi.json.model.DdiAssignedVersion; import org.eclipse.hawkbit.ddi.json.model.DdiConfirmationFeedback; @@ -131,7 +132,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat protected ResultActions putInstalledBase(final String controllerId, final String content, final ResultMatcher statusMatcher) throws Exception { - return mvc.perform(put(INSTALLED_BASE_ROOT, tenantAware.getCurrentTenant(), controllerId) + return mvc.perform(put(INSTALLED_BASE_ROOT, AccessContext.tenant(), controllerId) .content(content.getBytes()).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(statusMatcher); @@ -141,7 +142,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat final MediaType mediaType, final String controllerId, final Long actionId, final byte[] content, final ResultMatcher statusMatcher) throws Exception { return mvc - .perform(post(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), controllerId, actionId) + .perform(post(DEPLOYMENT_FEEDBACK, AccessContext.tenant(), controllerId, actionId) .content(content).contentType(mediaType).accept(mediaType)) .andDo(MockMvcResultPrinter.print()) .andExpect(statusMatcher); @@ -157,7 +158,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat final MediaType mediaType, final String controllerId, final Long actionId, final byte[] content, final ResultMatcher statusMatcher) throws Exception { return mvc - .perform(post(CANCEL_FEEDBACK, tenantAware.getCurrentTenant(), controllerId, actionId).content(content) + .perform(post(CANCEL_FEEDBACK, AccessContext.tenant(), controllerId, actionId).content(content) .contentType(mediaType).accept(mediaType)) .andDo(MockMvcResultPrinter.print()) .andExpect(statusMatcher); @@ -177,7 +178,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat final DistributionSet ds, final Artifact artifact, final Artifact artifactSignature, final Long actionId, final Long osModuleId, final String downloadType, final String updateType) throws Exception { final ResultActions resultActions = performGet(DEPLOYMENT_BASE, mediaType, status().isOk(), - tenantAware.getCurrentTenant(), controllerId, actionId.toString()); + AccessContext.tenant(), controllerId, actionId.toString()); return verifyBasePayload( "$.deployment", resultActions, controllerId, ds, artifact, artifactSignature, actionId, osModuleId, downloadType, updateType); } @@ -194,18 +195,18 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat final DistributionSet ds, final Artifact artifact, final Artifact artifactSignature, final Long actionId, final Long osModuleId, final Action.ActionType actionType) throws Exception { final ResultActions resultActions = performGet(INSTALLED_BASE, mediaType, status().isOk(), - tenantAware.getCurrentTenant(), controllerId, actionId.toString()); + AccessContext.tenant(), controllerId, actionId.toString()); return verifyBasePayload("$.deployment", resultActions, controllerId, ds, artifact, artifactSignature, actionId, osModuleId, getDownloadAndUploadType(actionType), getDownloadAndUploadType(actionType)); } protected String installedBaseLink(final String controllerId, final String actionId) { - return HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + + return HTTP_LOCALHOST + AccessContext.tenant() + "/controller/v1/" + controllerId + "/installedBase/" + actionId; } protected String deploymentBaseLink(final String controllerId, final String actionId) { - return HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + + return HTTP_LOCALHOST + AccessContext.tenant() + "/controller/v1/" + controllerId + "/deploymentBase/" + actionId; } @@ -319,7 +320,7 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat final Long osModuleId, final String downloadType, final String updateType) throws Exception { final ResultActions resultActions = performGet( CONFIRMATION_BASE_ACTION, mediaType, status().isOk(), - tenantAware.getCurrentTenant(), controllerId, actionId.toString()); + AccessContext.tenant(), controllerId, actionId.toString()); return verifyBasePayload( "$.confirmation", resultActions, controllerId, ds, artifact, artifactSignature, actionId, osModuleId, downloadType, updateType); @@ -367,10 +368,10 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat .andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[0].hashes.sha256", contains(artifact.getSha256Hash()))) .andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[0]._links.download-http.href", - contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId + + contains(HTTP_LOCALHOST + AccessContext.tenant() + "/controller/v1/" + controllerId + "/softwaremodules/" + osModuleId + "/artifacts/" + artifact.getFilename()))) .andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[0]._links.md5sum-http.href", - contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId + + contains(HTTP_LOCALHOST + AccessContext.tenant() + "/controller/v1/" + controllerId + "/softwaremodules/" + osModuleId + "/artifacts/" + artifact.getFilename() + ".MD5SUM"))) .andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1].size", contains(ARTIFACT_SIZE))) .andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1].filename", @@ -382,10 +383,10 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat .andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1].hashes.sha256", contains(artifactSignature.getSha256Hash()))) .andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1]._links.download-http.href", - contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId + + contains(HTTP_LOCALHOST + AccessContext.tenant() + "/controller/v1/" + controllerId + "/softwaremodules/" + osModuleId + "/artifacts/" + artifactSignature.getFilename()))) .andExpect(jsonPath(prefix + ".chunks[?(@.part=='os')].artifacts[1]._links.md5sum-http.href", - contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId + + contains(HTTP_LOCALHOST + AccessContext.tenant() + "/controller/v1/" + controllerId + "/softwaremodules/" + osModuleId + "/artifacts/" + artifactSignature.getFilename() + ".MD5SUM"))) .andExpect(jsonPath(prefix + ".chunks[?(@.part=='bApp')].version", contains(findFirstModuleByType(ds, appType).orElseThrow().getVersion()))) diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java index 58be27f93..198bef44d 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Locale; import java.util.TimeZone; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.rest.resource.DdiArtifactDownloadTest.DownloadTestConfiguration; import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent; import org.eclipse.hawkbit.repository.model.Artifact; @@ -106,55 +107,55 @@ class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest { // test now consistent data to test allowed methods mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()) .header(HttpHeaders.IF_MATCH, artifact.getSha1Hash())) .andExpect(status().isOk()); mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isOk()); // test failed If-match mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()) .header(HttpHeaders.IF_MATCH, "fsjkhgjfdhg")) .andExpect(status().isPreconditionFailed()); // test invalid range mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()) .header("Range", "bytes=1-10,hdsfjksdh")) .andExpect(header().string("Content-Range", "bytes */" + 5 * 1024)) .andExpect(status().isRequestedRangeNotSatisfiable()); mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()) .header("Range", "bytes=100-10")) .andExpect(header().string("Content-Range", "bytes */" + 5 * 1024)) .andExpect(status().isRequestedRangeNotSatisfiable()); // not allowed methods mvc.perform(put("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isMethodNotAllowed()); mvc.perform(delete("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isMethodNotAllowed()); mvc.perform(post("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isMethodNotAllowed()); mvc.perform(put("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isMethodNotAllowed()); mvc.perform(delete("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isMethodNotAllowed()); mvc.perform(post("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isMethodNotAllowed()); } @@ -193,7 +194,7 @@ class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest { assignDistributionSet(ds, targets); final MvcResult result = mvc.perform(get( "/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM)) .andExpect(header().string("Accept-Ranges", "bytes")) @@ -233,7 +234,7 @@ class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest { // download final MvcResult result = mvc.perform(get( "/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}.MD5SUM", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())) .andExpect(status().isOk()) .andExpect(header().string("Content-Disposition", "attachment;filename=" + artifact.getFilename() + ".MD5SUM")) @@ -278,7 +279,7 @@ class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest { final MvcResult result = mvc.perform(get( "/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1").header("Range", + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), "file1").header("Range", "bytes=" + rangeString)) .andExpect(status().isPartialContent()) .andExpect(header().string("ETag", artifact.getSha1Hash())) @@ -298,7 +299,7 @@ class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest { // return last 1000 Bytes MvcResult result = mvc.perform( get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1") + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), "file1") .header("Range", "bytes=-1000")) .andExpect(status().isPartialContent()) .andExpect(header().string("ETag", artifact.getSha1Hash())) @@ -317,7 +318,7 @@ class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest { // skip first 1000 Bytes and return the rest result = mvc.perform( get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1") + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), "file1") .header("Range", "bytes=1000-")) .andExpect(status().isPartialContent()) .andExpect(header().string("ETag", artifact.getSha1Hash())) @@ -335,7 +336,7 @@ class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest { // Start download from file end fails mvc.perform( get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1") + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), "file1") .header("Range", "bytes=" + random.length + "-")) .andExpect(status().isRequestedRangeNotSatisfiable()) .andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM)) @@ -347,7 +348,7 @@ class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest { // multipart download - first 20 bytes in 2 parts result = mvc.perform( get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}", - tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1") + AccessContext.tenant(), target.getControllerId(), getOsModule(ds), "file1") .header("Range", "bytes=0-9,10-19")) .andExpect(status().isPartialContent()) .andExpect(header().string("ETag", artifact.getSha1Hash())) diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiCancelActionTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiCancelActionTest.java index 89428220e..157ddbcde 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiCancelActionTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiCancelActionTest.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.json.model.DdiResult; import org.eclipse.hawkbit.ddi.json.model.DdiStatus; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; @@ -66,7 +67,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // check that we can get the cancel action as CBOR final byte[] result = mvc .perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId(), tenantAware.getCurrentTenant()) + + cancelAction.getId(), AccessContext.tenant()) .accept(DdiRestConstants.MEDIA_TYPE_CBOR)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -80,7 +81,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // and submit feedback as CBOR mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(jsonToCbor(getJsonProceedingCancelActionFeedback())) .contentType(DdiRestConstants.MEDIA_TYPE_CBOR).accept(DdiRestConstants.MEDIA_TYPE_CBOR)) .andDo(MockMvcResultPrinter.print()) @@ -104,7 +105,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // controller rejects cancellation mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonRejectedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -115,7 +116,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // get update action anyway mvc.perform( get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" + actionId, - tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)) + AccessContext.tenant()).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -131,7 +132,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // and finish it mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" - + actionId + "/feedback", tenantAware.getCurrentTenant()).content( + + actionId + "/feedback", AccessContext.tenant()).content( getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE, Collections.singletonList("message"))) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) @@ -161,14 +162,14 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { assignDistributionSet(ds.getId(), savedTarget.getControllerId())); final long timeBeforeFirstPoll = System.currentTimeMillis(); - mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(), + mvc.perform(get("/{tenant}/controller/v1/{controller}", AccessContext.tenant(), TestdataFactory.DEFAULT_CONTROLLER_ID).accept(MediaTypes.HAL_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.deploymentBase.href", - startsWith("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + startsWith("http://localhost/" + AccessContext.tenant() + "/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" + actionId))); final long timeAfterFirstPoll = System.currentTimeMillis() + 1; assertThat(targetManagement.getByControllerId(TestdataFactory.DEFAULT_CONTROLLER_ID).getLastTargetQuery()) @@ -192,21 +193,21 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { assertThat(activeActionsByTarget.get(0).getStatus()).isEqualTo(Status.CANCELING); final long timeBefore2ndPoll = System.currentTimeMillis(); - mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(), + mvc.perform(get("/{tenant}/controller/v1/{controller}", AccessContext.tenant(), TestdataFactory.DEFAULT_CONTROLLER_ID)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.cancelAction.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + equalTo("http://localhost/" + AccessContext.tenant() + "/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" + cancelAction.getId()))); final long timeAfter2ndPoll = System.currentTimeMillis() + 1; assertThat(targetManagement.getByControllerId(TestdataFactory.DEFAULT_CONTROLLER_ID).getLastTargetQuery()) .isBetween(timeBefore2ndPoll, timeAfter2ndPoll); mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId(), tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)) + + cancelAction.getId(), AccessContext.tenant()).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -217,7 +218,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // controller confirmed cancelled action, should not be active anymore mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON) + + cancelAction.getId() + "/feedback", AccessContext.tenant()).accept(MediaType.APPLICATION_JSON) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -240,22 +241,22 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // not allowed methods mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/1", - tenantAware.getCurrentTenant())) + AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); mvc.perform(put("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/1", - tenantAware.getCurrentTenant())) + AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); mvc.perform(delete("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/1", - tenantAware.getCurrentTenant())) + AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); // non existing target - mvc.perform(get("/{tenant}/controller/v1/34534543/cancelAction/1", tenantAware.getCurrentTenant()) + mvc.perform(get("/{tenant}/controller/v1/34534543/cancelAction/1", AccessContext.tenant()) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -263,7 +264,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { createCancelAction("34534543"); // wrong media type - mvc.perform(get("/{tenant}/controller/v1/34534543/cancelAction/1", tenantAware.getCurrentTenant()) + mvc.perform(get("/{tenant}/controller/v1/34534543/cancelAction/1", AccessContext.tenant()) .accept(MediaType.APPLICATION_ATOM_XML)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotAcceptable()); @@ -289,7 +290,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget.getControllerId(), PAGE)).hasSize(1); mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonProceedingCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -299,7 +300,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { assertThat(countActionStatusAll()).isEqualTo(3); mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonResumedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -308,7 +309,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { assertThat(countActionStatusAll()).isEqualTo(4); mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonScheduledCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -319,7 +320,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // cancellation canceled -> should remove the action from active assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget.getControllerId(), PAGE)).hasSize(1); mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonCanceledCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -333,7 +334,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // error assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget.getControllerId(), PAGE)).hasSize(1); mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonRejectedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -343,7 +344,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // update closed -> should remove the action from active mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -383,7 +384,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { assertThat(deploymentManagement.countActionsByTarget(savedTarget.getControllerId())).isEqualTo(3); mvc.perform(get( "/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" + cancelAction.getId(), - tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)) + AccessContext.tenant()).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -391,19 +392,19 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { .andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(actionId)))); assertThat(countActionStatusAll()).isEqualTo(6); - mvc.perform(get("/{tenant}/controller/v1/{controllerId}", tenantAware.getCurrentTenant(), + mvc.perform(get("/{tenant}/controller/v1/{controllerId}", AccessContext.tenant(), TestdataFactory.DEFAULT_CONTROLLER_ID)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.cancelAction.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + equalTo("http://localhost/" + AccessContext.tenant() + "/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" + cancelAction.getId()))); // now lets return feedback for the first cancelation mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -414,7 +415,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { assertThat(deploymentManagement.findActiveActionsByTarget(savedTarget.getControllerId(), PAGE)).hasSize(2); assertThat(deploymentManagement.countActionsByTarget(savedTarget.getControllerId())).isEqualTo(3); mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction2.getId(), tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)) + + cancelAction2.getId(), AccessContext.tenant()).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -422,19 +423,19 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { .andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(actionId2)))); assertThat(countActionStatusAll()).isEqualTo(8); - mvc.perform(get("/{tenant}/controller/v1/{controller}", tenantAware.getCurrentTenant(), + mvc.perform(get("/{tenant}/controller/v1/{controller}", AccessContext.tenant(), TestdataFactory.DEFAULT_CONTROLLER_ID)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.cancelAction.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + equalTo("http://localhost/" + AccessContext.tenant() + "/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" + cancelAction2.getId()))); // now lets return feedback for the second cancelation mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction2.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction2.getId() + "/feedback", AccessContext.tenant()) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -444,7 +445,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { assertThat(deploymentManagement.findAssignedDistributionSet(TestdataFactory.DEFAULT_CONTROLLER_ID).orElseThrow()).isEqualTo(ds3); mvc.perform( get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/deploymentBase/" + actionId3, - tenantAware.getCurrentTenant())) + AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); assertThat(countActionStatusAll()).isEqualTo(10); @@ -461,7 +462,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { mvc.perform(get( "/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" + cancelAction3.getId(), - tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)) + AccessContext.tenant()).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -471,7 +472,7 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // now lets return feedback for the third cancelation mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction3.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction3.getId() + "/feedback", AccessContext.tenant()) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -502,13 +503,13 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // only 97 action status left for (int i = 0; i < 98; i++) { mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(feedback) + + cancelAction.getId() + "/feedback", AccessContext.tenant()).content(feedback) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); } mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(feedback) + + cancelAction.getId() + "/feedback", AccessContext.tenant()).content(feedback) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isTooManyRequests()); } @@ -523,25 +524,25 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // not allowed methods mvc.perform(put("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); mvc.perform(delete("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())) + + cancelAction.getId() + "/feedback", AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); mvc.perform(get("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant())) + + cancelAction.getId() + "/feedback", AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); // bad content type mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_ATOM_XML) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -550,14 +551,14 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // bad body String invalidFeedback = "{\"status\":{\"execution\":\"546456456\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"none\"]}}"; mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(invalidFeedback) + + cancelAction.getId() + "/feedback", AccessContext.tenant()).content(invalidFeedback) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isBadRequest()); // non existing target mvc.perform(post("/{tenant}/controller/v1/12345/cancelAction/" + cancelAction.getId() + "/feedback", - tenantAware.getCurrentTenant()).content(getJsonClosedCancelActionFeedback()) + AccessContext.tenant()).content(getJsonClosedCancelActionFeedback()) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -565,14 +566,14 @@ class DdiCancelActionTest extends AbstractDDiApiIntegrationTest { // invalid action invalidFeedback = "{\"id\":\"sdfsdfsdfs\",\"status\":{\"execution\":\"closed\",\"result\":{\"finished\":\"none\",\"progress\":{\"cnt\":2,\"of\":5}},\"details\":\"details\"]}}"; mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()).content(invalidFeedback) + + cancelAction.getId() + "/feedback", AccessContext.tenant()).content(invalidFeedback) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isBadRequest()); // finaly, get it right :) mvc.perform(post("/{tenant}/controller/v1/" + TestdataFactory.DEFAULT_CONTROLLER_ID + "/cancelAction/" - + cancelAction.getId() + "/feedback", tenantAware.getCurrentTenant()) + + cancelAction.getId() + "/feedback", AccessContext.tenant()) .content(getJsonClosedCancelActionFeedback()).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfigDataTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfigDataTest.java index 0b66f205f..d4e299a06 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfigDataTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfigDataTest.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; @@ -62,7 +63,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { final Map attributes = new HashMap<>(); attributes.put(ATTRIBUTE_KEY_VALID, ATTRIBUTE_VALUE_VALID); - mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(jsonToCbor(JsonBuilder.configData(attributes).toString())) .contentType(DdiRestConstants.MEDIA_TYPE_CBOR)) .andDo(MockMvcResultPrinter.print()) @@ -80,13 +81,13 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { final Target savedTarget = testdataFactory.createTarget("4712"); final long current = System.currentTimeMillis(); - mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()).accept(MediaTypes.HAL_JSON)) + mvc.perform(get("/{tenant}/controller/v1/4712", AccessContext.tenant()).accept(MediaTypes.HAL_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.configData.href", equalTo( - "http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/configData"))); + "http://localhost/" + AccessContext.tenant() + "/controller/v1/4712/configData"))); Thread.sleep(1); // is required: otherwise processing the next line is // often too fast and // the following assert will fail assertThat(targetManagement.getByControllerId("4712") @@ -102,7 +103,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { // to request the controller attributes again assertThat(updateControllerAttributes.isRequestControllerAttributes()).isFalse(); - mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()).accept(MediaTypes.HAL_JSON)) + mvc.perform(get("/{tenant}/controller/v1/4712", AccessContext.tenant()).accept(MediaTypes.HAL_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) @@ -122,7 +123,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { final Map attributes = new HashMap<>(); attributes.put(ATTRIBUTE_KEY_VALID, ATTRIBUTE_VALUE_VALID); - mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); @@ -130,7 +131,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { // update attributes.put("sdsds", "123412"); - mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); @@ -150,12 +151,12 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { for (int i = 0; i < quotaManagement.getMaxAttributeEntriesPerTarget(); i++) { attributes.put("dsafsdf" + i, "sdsds" + i); } - mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(attributes).toString()) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); - mvc.perform(put(TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(Map.of("on too many", "sdsds")).toString()) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isTooManyRequests()) @@ -172,33 +173,33 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { testdataFactory.createTarget("4712"); // not allowed methods - mvc.perform(post("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant())) + mvc.perform(post("/{tenant}/controller/v1/4712/configData", AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()).// andExpect(status().isMethodNotAllowed()); - mvc.perform(get("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant())) + mvc.perform(get("/{tenant}/controller/v1/4712/configData", AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(delete("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant())) + mvc.perform(delete("/{tenant}/controller/v1/4712/configData", AccessContext.tenant())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); // bad content type final Map attributes = Map.of("dsafsdf", "sdsds"); - mvc.perform(put("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant()) + mvc.perform(put("/{tenant}/controller/v1/4712/configData", AccessContext.tenant()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaTypes.HAL_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isUnsupportedMediaType()); // non existing target - mvc.perform(put("/{tenant}/controller/v1/456456/configData", tenantAware.getCurrentTenant()) + mvc.perform(put("/{tenant}/controller/v1/456456/configData", AccessContext.tenant()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); // bad body - mvc.perform(put("/{tenant}/controller/v1/4712/configData", tenantAware.getCurrentTenant()) + mvc.perform(put("/{tenant}/controller/v1/4712/configData", AccessContext.tenant()) .content("{\"id\": \"51659181\"}").contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isBadRequest()); @@ -241,7 +242,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { private void putAndVerifyConfigDataWithKeyTooLong() throws Exception { final Map attributes = Collections.singletonMap(ATTRIBUTE_KEY_TOO_LONG, ATTRIBUTE_VALUE_VALID); - mvc.perform(put(DdiConfigDataTest.TARGET2_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(DdiConfigDataTest.TARGET2_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.exceptionClass", equalTo(InvalidTargetAttributeException.class.getName()))) @@ -250,7 +251,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { private void putAndVerifyConfigDataWithValueTooLong() throws Exception { final Map attributes = Collections.singletonMap(ATTRIBUTE_KEY_VALID, ATTRIBUTE_VALUE_TOO_LONG); - mvc.perform(put(DdiConfigDataTest.TARGET2_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(DdiConfigDataTest.TARGET2_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.exceptionClass", equalTo(InvalidTargetAttributeException.class.getName()))) @@ -264,7 +265,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { "k1", "v1"); // use an invalid update mode - mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(attributes, "KJHGKJHGKJHG").toString()) .contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -280,7 +281,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { "k1", "foo", "k3", "bar"); - mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(removeAttributes, "remove").toString()) .contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -302,7 +303,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { final Map mergeAttributes = Map.of( "k1", "v1_modified_again", "k4", "v4"); - mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(mergeAttributes, "merge").toString()) .contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -325,7 +326,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { "k1", "v1_modified", "k2", "v2", "k3", "v3"); - mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(replacementAttributes, "replace").toString()) .contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -346,7 +347,7 @@ class DdiConfigDataTest extends AbstractDDiApiIntegrationTest { "k1", "v1"); // set the initial attributes - mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, tenantAware.getCurrentTenant()) + mvc.perform(put(DdiConfigDataTest.TARGET1_CONFIG_DATA_PATH, AccessContext.tenant()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfirmationBaseTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfirmationBaseTest.java index b0bd6e0a8..694f0a52f 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfirmationBaseTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiConfirmationBaseTest.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Stream; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.json.model.DdiActivateAutoConfirmation; import org.eclipse.hawkbit.ddi.json.model.DdiConfirmationFeedback; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; @@ -106,9 +107,9 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { final long current = System.currentTimeMillis(); final String expectedConfirmationBaseLink = String.format( "/%s/controller/v1/%s/confirmationBase/%d", - tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, uaction.getId()); + AccessContext.tenant(), DEFAULT_CONTROLLER_ID, uaction.getId()); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), DEFAULT_CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.confirmationBase.href", containsString(expectedConfirmationBaseLink))) .andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist()); @@ -150,11 +151,11 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { // get confirmation base performGet(CONFIRMATION_BASE_ACTION, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), - status().isOk(), tenantAware.getCurrentTenant(), target.getControllerId(), action.getId().toString()); + status().isOk(), AccessContext.tenant(), target.getControllerId(), action.getId().toString()); // get artifacts performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), - status().isOk(), tenantAware.getCurrentTenant(), target.getControllerId(), + status().isOk(), AccessContext.tenant(), target.getControllerId(), String.valueOf(softwareModuleId)); } @@ -170,12 +171,12 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { final String controllerId = savedTarget.getControllerId(); final Action savedAction = deploymentManagement.findActiveActionsByTarget(controllerId, PAGE).getContent().get(0); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.confirmationBase.href").doesNotExist()); - mvc.perform(get(CONFIRMATION_BASE_ACTION, tenantAware.getCurrentTenant(), controllerId, savedAction.getId()) + mvc.perform(get(CONFIRMATION_BASE_ACTION, AccessContext.tenant(), controllerId, savedAction.getId()) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -195,18 +196,18 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { final String controllerId = savedTarget.getControllerId(); final Action savedAction = deploymentManagement.findActiveActionsByTarget(controllerId, PAGE).getContent().get(0); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.confirmationBase.href").exists()) .andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist()); - mvc.perform(get(CONFIRMATION_BASE_ACTION, tenantAware.getCurrentTenant(), controllerId, savedAction.getId()) + mvc.perform(get(CONFIRMATION_BASE_ACTION, AccessContext.tenant(), controllerId, savedAction.getId()) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); - mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), controllerId, savedAction.getId()) + mvc.perform(get(DEPLOYMENT_BASE, AccessContext.tenant(), controllerId, savedAction.getId()) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -300,13 +301,13 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { final String confirmationBaseActionLink = String.format( "/%s/controller/v1/%s/confirmationBase/%d", - tenantAware.getCurrentTenant(), controllerId, actionId); + AccessContext.tenant(), controllerId, actionId); final String activateAutoConfLink = String.format( "/%s/controller/v1/%s/confirmationBase/activateAutoConfirm", - tenantAware.getCurrentTenant(), controllerId); + AccessContext.tenant(), controllerId); - mvc.perform(get(CONFIRMATION_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONFIRMATION_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("autoConfirm.active", equalTo(Boolean.FALSE))) @@ -327,9 +328,9 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { final String deactivateAutoConfLink = String.format( "/%s/controller/v1/%s/confirmationBase/deactivateAutoConfirm", - tenantAware.getCurrentTenant(), controllerId); + AccessContext.tenant(), controllerId); - mvc.perform(get(CONFIRMATION_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONFIRMATION_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("autoConfirm.active", equalTo(Boolean.TRUE))) @@ -353,7 +354,7 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { final DdiActivateAutoConfirmation body = new DdiActivateAutoConfirmation(initiator, remark); - mvc.perform(post(ACTIVATE_AUTO_CONFIRM, tenantAware.getCurrentTenant(), controllerId) + mvc.perform(post(ACTIVATE_AUTO_CONFIRM, AccessContext.tenant(), controllerId) .content(getMapper().writeValueAsString(body)).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); @@ -374,7 +375,7 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { confirmationManagement.activateAutoConfirmation(controllerId, null, null); - mvc.perform(post(DEACTIVATE_AUTO_CONFIRM, tenantAware.getCurrentTenant(), controllerId)) + mvc.perform(post(DEACTIVATE_AUTO_CONFIRM, AccessContext.tenant(), controllerId)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); @@ -414,15 +415,15 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { // asserts that deployment link is not available final String expectedConfirmationBaseLink = String.format( "/%s/controller/v1/%s/confirmationBase/%d", - tenantAware.getCurrentTenant(), controllerId, savedAction.getId()); + AccessContext.tenant(), controllerId, savedAction.getId()); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist()) .andExpect(jsonPath("$._links.confirmationBase.href", containsString(expectedConfirmationBaseLink))); - mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), controllerId, savedAction.getId()) + mvc.perform(get(DEPLOYMENT_BASE, AccessContext.tenant(), controllerId, savedAction.getId()) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -460,14 +461,14 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { .andExpect(status().isOk()); // confirmationBase not available in RUNNING state anymore - mvc.perform(get(CONFIRMATION_BASE_ACTION, tenantAware.getCurrentTenant(), savedTarget.getControllerId(), + mvc.perform(get(CONFIRMATION_BASE_ACTION, AccessContext.tenant(), savedTarget.getControllerId(), savedAction.getId()).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); // assert confirmed message against deploymentBase endpoint // this call will update the action due to retrieved action status update - mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), savedTarget.getControllerId(), + mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", AccessContext.tenant(), savedTarget.getControllerId(), savedAction.getId()).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -487,9 +488,9 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { private void verifyActionInDeploymentBaseState(final String controllerId, final long actionId) throws Exception { final String expectedDeploymentBaseLink = String.format( "/%s/controller/v1/%s/deploymentBase/%d", - tenantAware.getCurrentTenant(), controllerId, actionId); + AccessContext.tenant(), controllerId, actionId); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.deploymentBase.href", containsString(expectedDeploymentBaseLink))) @@ -502,18 +503,18 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { } private void verifyActionInConfirmationBaseState(final String controllerId, final long actionId) throws Exception { - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.confirmationBase.href").exists()) .andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist()); - mvc.perform(get(CONFIRMATION_BASE_ACTION, tenantAware.getCurrentTenant(), controllerId, actionId) + mvc.perform(get(CONFIRMATION_BASE_ACTION, AccessContext.tenant(), controllerId, actionId) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); - mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), controllerId, actionId) + mvc.perform(get(DEPLOYMENT_BASE, AccessContext.tenant(), controllerId, actionId) .accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -528,7 +529,7 @@ class DdiConfirmationBaseTest extends AbstractDDiApiIntegrationTest { final String feedback = getJsonConfirmationFeedback(confirmation, code, Collections.singletonList(message)); return mvc.perform( - post(CONFIRMATION_FEEDBACK, tenantAware.getCurrentTenant(), target.getControllerId(), action.getId()) + post(CONFIRMATION_FEEDBACK, AccessContext.tenant(), target.getControllerId(), action.getId()) .content(feedback).contentType(MediaType.APPLICATION_JSON)); } } \ No newline at end of file diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java index bf0dc06cd..48e97833d 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiDeploymentBaseTest.java @@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit; import com.jayway.jsonpath.JsonPath; import org.assertj.core.api.Condition; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.json.model.DdiResult; import org.eclipse.hawkbit.ddi.json.model.DdiStatus; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; @@ -96,11 +97,11 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { // get deployment base performGet(DEPLOYMENT_BASE, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(), - tenantAware.getCurrentTenant(), target.getControllerId(), action.getId().toString()); + AccessContext.tenant(), target.getControllerId(), action.getId().toString()); // get artifacts performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), - status().isOk(), tenantAware.getCurrentTenant(), target.getControllerId(), + status().isOk(), AccessContext.tenant(), target.getControllerId(), String.valueOf(softwareModuleId)); final byte[] feedback = jsonToCbor(getJsonProceedingDeploymentActionFeedback()); @@ -115,7 +116,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { @Test void artifactsNotFound() throws Exception { final Target target = testdataFactory.createTarget(); - performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isNotFound(), tenantAware.getCurrentTenant(), + performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isNotFound(), AccessContext.tenant(), target.getControllerId(), "1"); } @@ -132,7 +133,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { assignDistributionSet(distributionSet.getId(), target.getName()); - performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(), AccessContext.tenant(), target.getControllerId(), softwareModuleId.toString()) .andExpect(jsonPath("$", hasSize(3))) .andExpect(jsonPath("$.[?(@.filename=='filename0')]", hasSize(1))) @@ -174,7 +175,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { // Run test final long current = System.currentTimeMillis(); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), DEFAULT_CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath( @@ -209,14 +210,14 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { ActionType.TIMEFORCED, System.currentTimeMillis() + 2_000)); MvcResult mvcResult = performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), - tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID) + AccessContext.tenant(), DEFAULT_CONTROLLER_ID) .andReturn(); final String urlBeforeSwitch = JsonPath.compile("_links.deploymentBase.href") .read(mvcResult.getResponse().getContentAsString()).toString(); // Time is not yet over, so we should see the same URL - mvcResult = performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), + mvcResult = performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), DEFAULT_CONTROLLER_ID) .andReturn(); assertThat(JsonPath.compile("_links.deploymentBase.href").read(mvcResult.getResponse().getContentAsString()) @@ -226,7 +227,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { // After the time is over we should see a new etag TimeUnit.MILLISECONDS.sleep(2_000); - mvcResult = performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), + mvcResult = performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), DEFAULT_CONTROLLER_ID) .andReturn(); @@ -272,7 +273,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { // Run test final long current = System.currentTimeMillis(); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), DEFAULT_CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.deploymentBase.href", @@ -326,7 +327,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { // Run test final long current = System.currentTimeMillis(); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), DEFAULT_CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.deploymentBase.href", @@ -388,7 +389,7 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { // Run test final long current = System.currentTimeMillis(); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), DEFAULT_CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.deploymentBase.href", startsWith(deploymentBaseLink(DEFAULT_CONTROLLER_ID, uaction.getId().toString())))); @@ -416,25 +417,25 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { final Target target = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID); // not allowed methods - mvc.perform(post(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1")) + mvc.perform(post(DEPLOYMENT_BASE, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(put(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1")) + mvc.perform(put(DEPLOYMENT_BASE, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(delete(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1")) + mvc.perform(delete(DEPLOYMENT_BASE, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); // non existing target - mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "not-existing", "1")) + mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, AccessContext.tenant(), "not-existing", "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); // no deployment - mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "1")) + mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -443,12 +444,12 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { final DistributionSet savedSet = testdataFactory.createDistributionSet(""); final Long actionId = getFirstAssignedActionId(assignDistributionSet(savedSet, toAssign)); - mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, + mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_BASE, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, actionId)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); mvc.perform(MockMvcRequestBuilders - .get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, actionId) + .get(DEPLOYMENT_BASE, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, actionId) .accept(MediaType.APPLICATION_ATOM_XML)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotAcceptable()); @@ -643,16 +644,16 @@ class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest { DdiResult.FinalResult.NONE, Collections.singletonList("")), status().isNotFound()); // not allowed methods - mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), + mvc.perform(MockMvcRequestBuilders.get(DEPLOYMENT_FEEDBACK, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, "2")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(put(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "2")) + mvc.perform(put(DEPLOYMENT_FEEDBACK, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, "2")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(delete(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), DEFAULT_CONTROLLER_ID, "2")) + mvc.perform(delete(DEPLOYMENT_FEEDBACK, AccessContext.tenant(), DEFAULT_CONTROLLER_ID, "2")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); } diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiInstalledBaseTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiInstalledBaseTest.java index 05c3a34cc..70d6fa431 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiInstalledBaseTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiInstalledBaseTest.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Stream; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.json.model.DdiResult; import org.eclipse.hawkbit.ddi.json.model.DdiStatus; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; @@ -90,11 +91,11 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { // get installed base performGet(INSTALLED_BASE, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), status().isOk(), - tenantAware.getCurrentTenant(), target.getControllerId(), actionId.toString()); + AccessContext.tenant(), target.getControllerId(), actionId.toString()); // get artifacts performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.parseMediaType(DdiRestConstants.MEDIA_TYPE_CBOR), - status().isOk(), tenantAware.getCurrentTenant(), target.getControllerId(), + status().isOk(), AccessContext.tenant(), target.getControllerId(), String.valueOf(softwareModuleId)); } @@ -153,7 +154,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { // Run test with 1st action final Long actionId1 = getFirstAssignedActionId( assignDistributionSet(ds1.getId(), target.getControllerId(), Action.ActionType.SOFT)); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.installedBase.href").doesNotExist()) .andExpect(jsonPath("$._links.deploymentBase.href", @@ -172,7 +173,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { // Run test with 2nd action final Long actionId2 = getFirstAssignedActionId( assignDistributionSet(ds2.getId(), target.getControllerId(), Action.ActionType.FORCED)); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.installedBase.href", startsWith(installedBaseLink(CONTROLLER_ID, actionId1.toString())))) @@ -189,7 +190,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds2, artifact2, artifactSignature2, actionId2, findFirstModuleByType(ds2, osType).orElseThrow().getId(), Action.ActionType.FORCED); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.installedBase.href", startsWith(installedBaseLink(CONTROLLER_ID, actionId2.toString())))) @@ -238,7 +239,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { status().isOk()); // Test: latest succeeded action is returned in installedBase - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.installedBase.href", startsWith(installedBaseLink(CONTROLLER_ID, actionId3.toString())))) @@ -248,11 +249,11 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { actionId3, findFirstModuleByType(ds1, osType).orElseThrow().getId(), Action.ActionType.SOFT); // cancelled action are not accessible - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(), + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), target.getControllerId(), actionId1.toString())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(), + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), target.getControllerId(), actionId2.toString())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -297,7 +298,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { // Test: the succeeded action is returned in installedBase instead of the latest // cancelled action - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.installedBase.href", startsWith(installedBaseLink(CONTROLLER_ID, actionId1.toString())))) @@ -307,11 +308,11 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { actionId1, findFirstModuleByType(ds1, osType).orElseThrow().getId(), Action.ActionType.SOFT); // cancelled action are not accessible - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(), + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), target.getControllerId(), actionId2.toString())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(), + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), target.getControllerId(), actionId3.toString())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -351,7 +352,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { status().isOk()); // Test: the succeeded action is returned in installedBase instead of the latest cancelled action - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.installedBase.href", startsWith(installedBaseLink(CONTROLLER_ID, actionId1.toString())))) @@ -362,11 +363,11 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { actionId1, findFirstModuleByType(ds1, osType).orElseThrow().getId(), Action.ActionType.SOFT); // cancelled action are not accessible - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(), + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), target.getControllerId(), actionId2.toString())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(), + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), target.getControllerId(), actionId3.toString())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -382,16 +383,16 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { final DistributionSet ds = testdataFactory.createDistributionSet(""); final Long actionId = getFirstAssignedActionId(assignDistributionSet(ds, target)); - performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(), CONTROLLER_ID) + performGet(CONTROLLER_BASE, MediaTypes.HAL_JSON, status().isOk(), AccessContext.tenant(), CONTROLLER_ID) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andExpect(jsonPath("$._links.installedBase.href").doesNotExist()) .andExpect(jsonPath("$._links.deploymentBase.href", startsWith(deploymentBaseLink(CONTROLLER_ID, actionId.toString())))); - performGet(DEPLOYMENT_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(DEPLOYMENT_BASE, MediaType.APPLICATION_JSON, status().isOk(), AccessContext.tenant(), target.getControllerId(), actionId.toString()); - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), target.getControllerId(), + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), target.getControllerId(), actionId.toString())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -413,7 +414,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { postDeploymentFeedback(target.getControllerId(), actionId, getJsonClosedDeploymentActionFeedback(), status().isOk()); performGet(SOFTWARE_MODULE_ARTIFACTS, MediaType.APPLICATION_JSON, status().isOk(), - tenantAware.getCurrentTenant(), target.getControllerId(), softwareModuleId.toString()) + AccessContext.tenant(), target.getControllerId(), softwareModuleId.toString()) .andExpect(jsonPath("$", hasSize(3))) .andExpect(jsonPath("$.[?(@.filename=='filename0')]", hasSize(1))) .andExpect(jsonPath("$.[?(@.filename=='filename1')]", hasSize(1))) @@ -454,13 +455,13 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { // Run test final ResultActions resultActions = performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), - tenantAware.getCurrentTenant(), target.getControllerId()); + AccessContext.tenant(), target.getControllerId()); resultActions.andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.deploymentBase.href").doesNotExist()) .andExpect(jsonPath("$._links.installedBase.href", containsString(String.format( "/%s/controller/v1/%s/installedBase/%d", - tenantAware.getCurrentTenant(), target.getControllerId(), actionId)))); + AccessContext.tenant(), target.getControllerId(), actionId)))); getAndVerifyInstalledBasePayload(CONTROLLER_ID, MediaType.APPLICATION_JSON, ds, artifact, artifactSignature, actionId, findFirstModuleByType(ds, osType).orElseThrow().getId(), actionType); @@ -499,7 +500,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { final Long actionId = getFirstAssignedActionId( assignDistributionSet(ds.getId(), target.getControllerId(), Action.ActionType.DOWNLOAD_ONLY)); - performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), AccessContext.tenant(), target.getControllerId()) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -510,7 +511,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { postDeploymentFeedback(target.getControllerId(), actionId, getJsonDownloadedDeploymentActionFeedback(), status().isOk()); // Test - performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), AccessContext.tenant(), target.getControllerId()) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -530,7 +531,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { final Long actionId = getFirstAssignedActionId( assignDistributionSet(ds.getId(), target.getControllerId(), actionType)); - performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), AccessContext.tenant(), target.getControllerId()) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -546,7 +547,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { status().isOk()); // Test - performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), tenantAware.getCurrentTenant(), + performGet(CONTROLLER_BASE, MediaType.APPLICATION_JSON, status().isOk(), AccessContext.tenant(), target.getControllerId()) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -581,14 +582,14 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { // Test // for zero input no action history is returned - mvc.perform(get(INSTALLED_BASE + "?actionHistory", tenantAware.getCurrentTenant(), 911, savedAction.getId()) + mvc.perform(get(INSTALLED_BASE + "?actionHistory", AccessContext.tenant(), 911, savedAction.getId()) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.actionHistory.messages").doesNotExist()); // depending on given query parameter value, only the latest messages are returned - mvc.perform(get(INSTALLED_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), 911, savedAction.getId()) + mvc.perform(get(INSTALLED_BASE + "?actionHistory=2", AccessContext.tenant(), 911, savedAction.getId()) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -598,7 +599,7 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { jsonPath("$.actionHistory.messages", not(hasItem(containsString("Installation scheduled"))))); // for negative input the entire action history is returned - mvc.perform(get(INSTALLED_BASE + "?actionHistory=-3", tenantAware.getCurrentTenant(), 911, savedAction.getId()) + mvc.perform(get(INSTALLED_BASE + "?actionHistory=-3", AccessContext.tenant(), 911, savedAction.getId()) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -615,25 +616,25 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { final Target target = testdataFactory.createTarget(CONTROLLER_ID); // not allowed methods - mvc.perform(post(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, "1")) + mvc.perform(post(INSTALLED_BASE, AccessContext.tenant(), CONTROLLER_ID, "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(put(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, "1")) + mvc.perform(put(INSTALLED_BASE, AccessContext.tenant(), CONTROLLER_ID, "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); - mvc.perform(delete(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, "1")) + mvc.perform(delete(INSTALLED_BASE, AccessContext.tenant(), CONTROLLER_ID, "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); // non existing target - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), "not-existing", "1")) + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), "not-existing", "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); // no deployment - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, "1")) + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), CONTROLLER_ID, "1")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); @@ -643,10 +644,10 @@ class DdiInstalledBaseTest extends AbstractDDiApiIntegrationTest { final Long actionId = getFirstAssignedActionId(assignDistributionSet(savedSet, toAssign)); postDeploymentFeedback(CONTROLLER_ID, actionId, getJsonClosedCancelActionFeedback(), status().isOk()); - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId)) + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), CONTROLLER_ID, actionId)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); - mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, tenantAware.getCurrentTenant(), CONTROLLER_ID, actionId) + mvc.perform(MockMvcRequestBuilders.get(INSTALLED_BASE, AccessContext.tenant(), CONTROLLER_ID, actionId) .accept(MediaType.APPLICATION_ATOM_XML)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotAcceptable()); diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java index bef2d0e7f..ae948d2b6 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java @@ -10,8 +10,8 @@ package org.eclipse.hawkbit.ddi.rest.resource; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.im.authentication.SpPermission.TENANT_CONFIGURATION; -import static org.eclipse.hawkbit.im.authentication.SpRole.CONTROLLER_ROLE_ANONYMOUS; +import static org.eclipse.hawkbit.auth.SpPermission.TENANT_CONFIGURATION; +import static org.eclipse.hawkbit.auth.SpRole.CONTROLLER_ROLE_ANONYMOUS; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.callAs; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.getAs; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.withController; @@ -37,10 +37,11 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.Callable; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ddi.json.model.DdiResult; import org.eclipse.hawkbit.ddi.json.model.DdiStatus; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; -import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent; import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent; @@ -65,7 +66,7 @@ import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.utils.IpUtil; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.MediaTypes; @@ -93,7 +94,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { */ @Test void rootPollResourceCbor() throws Exception { - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711).accept(DdiRestConstants.MEDIA_TYPE_CBOR)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), 4711).accept(DdiRestConstants.MEDIA_TYPE_CBOR)) .andDo(MockMvcResultPrinter.print()) .andExpect(content().contentType(DdiRestConstants.MEDIA_TYPE_CBOR)) .andExpect(status().isOk()); @@ -104,7 +105,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { */ @Test void apiReturnsJSONByDefault() throws Exception { - final MvcResult result = mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711)) + final MvcResult result = mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), 4711)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) @@ -132,7 +133,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { // make a poll, audit information should not be changed, run as controller principal! callAs(withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownTargetControllerId)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), knownTargetControllerId)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); return null; @@ -205,7 +206,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { withPollingTime("00:02:00", () -> callAs( withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), 4711)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) @@ -226,7 +227,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Expect(type = TenantConfigurationCreatedEvent.class, count = 1), @Expect(type = TenantConfigurationDeletedEvent.class, count = 1) }) void pollWithModifiedWithOverridesGlobalPollingTime() throws Exception { - SecurityContextSwitch.callAsPrivileged(() -> { + SecurityContextSwitch.asPrivileged(() -> { final Target target = testdataFactory.createTarget("not4711"); targetManagement.assignTargetsWithGroup("Europe", List.of(target.getControllerId())); return null; @@ -235,13 +236,13 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { withPollingTime("00:02:00, controllerid == 4711 -> 00:01:00, group == 'Europe' -> 00:05:05", () -> callAs( withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), 4711)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), 4711)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), "not4711")) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), "not4711")) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) @@ -268,7 +269,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Expect(type = TargetAttributesRequestedEvent.class, count = 1) }) void rootRsNotModified() throws Exception { final String controllerId = "4711"; - final String etag = mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId)) + final String etag = mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) @@ -276,7 +277,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { .andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))) .andReturn().getResponse() .getHeader("ETag"); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).header("If-None-Match", etag)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).header("If-None-Match", etag)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotModified()); @@ -286,7 +287,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { final Action updateAction = deploymentManagement.findActiveActionsByTarget(target.getControllerId(), PAGE).getContent().get(0); final String etagWithFirstUpdate = mvc - .perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId) + .perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId) .header("If-None-Match", etag) .accept(MediaType.APPLICATION_JSON) .with(new RequestOnHawkbitDefaultPortPostProcessor())) @@ -299,7 +300,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { startsWith(deploymentBaseLink("4711", updateAction.getId().toString())))) .andReturn().getResponse().getHeader("ETag"); assertThat(etagWithFirstUpdate).isNotNull(); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).header("If-None-Match", + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).header("If-None-Match", etagWithFirstUpdate).with(new RequestOnHawkbitDefaultPortPostProcessor())) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotModified()); @@ -311,7 +312,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { // as the update was installed, and we always receive the installed action, the // original state cannot be restored final String etagAfterInstallation = mvc - .perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId) + .perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId) .header("If-None-Match", etag).accept(MediaType.APPLICATION_JSON) .with(new RequestOnHawkbitDefaultPortPostProcessor())) .andDo(MockMvcResultPrinter.print()) @@ -327,7 +328,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { final DistributionSet ds2 = testdataFactory.createDistributionSet("2"); assignDistributionSet(ds2.getId(), controllerId); final Action updateAction2 = deploymentManagement.findActiveActionsByTarget(target.getControllerId(), PAGE).getContent().get(0); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId) .header("If-None-Match", etagAfterInstallation).accept(MediaType.APPLICATION_JSON) .with(new RequestOnHawkbitDefaultPortPostProcessor())) .andDo(MockMvcResultPrinter.print()) @@ -355,7 +356,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { testdataFactory.createTarget(controllerId); assertThat(targetManagement.getByControllerId(controllerId).getUpdateStatus()).isEqualTo(TargetUpdateStatus.UNKNOWN); final long current = System.currentTimeMillis(); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaTypes.HAL_JSON)) @@ -382,7 +383,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { // make a poll, audit information should be set on plug and play callAs(withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownControllerId1)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), knownControllerId1)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); return null; @@ -408,7 +409,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { securityProperties.getClients().setTrackRemoteIp(false); // test final String knownControllerId1 = "0815"; - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), knownControllerId1)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), knownControllerId1)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // verify @@ -468,7 +469,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { final Target savedTarget = testdataFactory.createTarget("922"); final Map attributes = Collections.singletonMap("AttributeKey", "AttributeValue"); assertThatAttributesUpdateIsRequested(savedTarget.getControllerId()); - mvc.perform(put(CONTROLLER_BASE + "/configData", tenantAware.getCurrentTenant(), savedTarget.getControllerId()) + mvc.perform(put(CONTROLLER_BASE + "/configData", AccessContext.tenant(), savedTarget.getControllerId()) .content(JsonBuilder.configData(attributes).toString()).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); assertThatAttributesUpdateIsNotRequested(savedTarget.getControllerId()); @@ -505,7 +506,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "success", TARGET_COMPLETED_INSTALLATION_MSG) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); - mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", tenantAware.getCurrentTenant(), 911, savedAction.getId()) + mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=2", AccessContext.tenant(), 911, savedAction.getId()) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -543,12 +544,12 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "success", TARGET_COMPLETED_INSTALLATION_MSG) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); - mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=0", tenantAware.getCurrentTenant(), 911, savedAction.getId()) + mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=0", AccessContext.tenant(), 911, savedAction.getId()) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.actionHistory.messages").doesNotExist()); - mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory", tenantAware.getCurrentTenant(), 911, savedAction.getId()) + mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory", AccessContext.tenant(), 911, savedAction.getId()) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -584,7 +585,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { sendDeploymentActionFeedback(savedTarget, savedAction, "closed", "success", TARGET_COMPLETED_INSTALLATION_MSG) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); - mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=-1", tenantAware.getCurrentTenant(), 911, savedAction.getId()) + mvc.perform(get(DEPLOYMENT_BASE + "?actionHistory=-1", AccessContext.tenant(), 911, savedAction.getId()) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) @@ -602,7 +603,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { getAs(withUser("tenantadmin", TENANT_CONFIGURATION), () -> { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME, "00:05:00"); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME, "00:05:00"); return null; }); @@ -657,7 +658,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { mvc.perform(get(CONTROLLER_BASE, "default-tenant", "1911")).andExpect(status().isOk()); final Action action = deploymentManagement.findActiveActionsByTarget(savedTarget.getControllerId(), PAGE).getContent().get(0); - mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", action.getId()).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(DEPLOYMENT_BASE, AccessContext.tenant(), "1911", action.getId()).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.deployment.download", equalTo("forced"))) @@ -678,7 +679,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { mvc.perform(get(CONTROLLER_BASE, "default-tenant", "1911")).andExpect(status().isOk()); final Action action = deploymentManagement.findActiveActionsByTarget(savedTarget.getControllerId(), PAGE).getContent().get(0); - mvc.perform(get(DEPLOYMENT_BASE, tenantAware.getCurrentTenant(), "1911", action.getId()).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(DEPLOYMENT_BASE, AccessContext.tenant(), "1911", action.getId()).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.deployment.download", equalTo("forced"))) @@ -709,7 +710,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Test void rootRsWithInvalidControllerId() throws Exception { final String invalidControllerId = randomString(Target.CONTROLLER_ID_MAX_SIZE + 1); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), invalidControllerId)).andExpect(status().isBadRequest()); + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), invalidControllerId)).andExpect(status().isBadRequest()); } private void assertAttributesUpdateNotRequestedAfterFailedDeployment(Target target, final DistributionSet ds) throws Exception { @@ -727,13 +728,13 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { } private void assertThatAttributesUpdateIsRequested(final String targetControllerId) throws Exception { - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), targetControllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), targetControllerId).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.configData.href").isNotEmpty()); } private void assertThatAttributesUpdateIsNotRequested(final String targetControllerId) throws Exception { - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), targetControllerId).accept(MediaType.APPLICATION_JSON)) + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), targetControllerId).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.configData").doesNotExist()); } @@ -749,7 +750,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { final String feedback = getJsonActionFeedback(DdiStatus.ExecutionStatus.valueOf(execution.toUpperCase()), DdiResult.FinalResult.valueOf(finished.toUpperCase()), Collections.singletonList(message)); - return mvc.perform(post(DEPLOYMENT_FEEDBACK, tenantAware.getCurrentTenant(), target.getControllerId(), action.getId()) + return mvc.perform(post(DEPLOYMENT_FEEDBACK, AccessContext.tenant(), target.getControllerId(), action.getId()) .content(feedback).contentType(MediaType.APPLICATION_JSON)); } @@ -761,8 +762,8 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { private void assertDeploymentActionIsExposedToTarget(final String controllerId, final long expectedActionId) throws Exception { final String expectedDeploymentBaseLink = String.format( "/%s/controller/v1/%s/deploymentBase/%d", - tenantAware.getCurrentTenant(), controllerId, expectedActionId); - mvc.perform(get(CONTROLLER_BASE, tenantAware.getCurrentTenant(), controllerId).accept(MediaType.APPLICATION_JSON)) + AccessContext.tenant(), controllerId, expectedActionId); + mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$._links.deploymentBase.href", containsString(expectedDeploymentBaseLink))); @@ -771,7 +772,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { private void withPollingTime(final String pollingTime, final Callable runnable) throws Exception { getAs(withUser("tenantadmin", TENANT_CONFIGURATION), () -> { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME, pollingTime); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME, pollingTime); return null; }); try { @@ -779,7 +780,7 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { } finally { getAs(withUser("tenantadmin", TENANT_CONFIGURATION), () -> { - tenantConfigurationManagement.deleteConfiguration(TenantConfigurationKey.POLLING_TIME); + tenantConfigurationManagement().deleteConfiguration(TenantConfigurationKey.POLLING_TIME); return null; }); } diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java index 97934ff60..d255764b2 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java @@ -17,6 +17,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.Collections; import java.util.List; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; @@ -53,20 +54,20 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest { */ @Test void blackListedClientIsForbidden() throws Exception { - mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + mvc.perform(get("/{tenant}/controller/v1/4711", AccessContext.tenant()) .header(X_FORWARDED_FOR, "192.168.0.4 , 10.0.0.1 ")) .andExpect(status().isForbidden()); } /** - * Ensures that a READ DoS attempt is blocked + * Ensures that a READ DoS attempt is blocked */ @Test void getFloodingAttackThatIsPrevented() throws Exception { int requests = 0; MvcResult result; do { - result = mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + result = mvc.perform(get("/{tenant}/controller/v1/4711", AccessContext.tenant()) .header(X_FORWARDED_FOR, "10.0.0.1")) .andReturn(); requests++; @@ -85,7 +86,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest { @Test void unacceptableGetLoadButOnWhitelistIPv4() throws Exception { for (int i = 0; i < 100; i++) { - mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + mvc.perform(get("/{tenant}/controller/v1/4711", AccessContext.tenant()) .header(X_FORWARDED_FOR, "127.0.0.1")) .andExpect(status().isOk()); } @@ -97,7 +98,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest { @Test void unacceptableGetLoadButOnWhitelistIPv6() throws Exception { for (int i = 0; i < 100; i++) { - mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + mvc.perform(get("/{tenant}/controller/v1/4711", AccessContext.tenant()) .header(X_FORWARDED_FOR, "0:0:0:0:0:0:0:1")) .andExpect(status().isOk()); } @@ -114,7 +115,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest { // sleep for one second Thread.sleep(1100); for (int i = 0; i < 9; i++) { - mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()) + mvc.perform(get("/{tenant}/controller/v1/4711", AccessContext.tenant()) .header(X_FORWARDED_FOR, "10.0.0.1")) .andExpect(status().isOk()); } @@ -122,7 +123,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest { } /** - * Ensures that a WRITE DoS attempt is blocked + * Ensures that a WRITE DoS attempt is blocked */ @Test void putPostFloddingAttackThatisPrevented() throws Exception { @@ -133,7 +134,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest { MvcResult result; do { result = mvc.perform(post("/{tenant}/controller/v1/4711/deploymentBase/" + actionId + "/feedback", - tenantAware.getCurrentTenant()).header(X_FORWARDED_FOR, "10.0.0.1").content(feedback) + AccessContext.tenant()).header(X_FORWARDED_FOR, "10.0.0.1").content(feedback) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andReturn(); requests++; @@ -162,7 +163,7 @@ class DosFilterTest extends AbstractDDiApiIntegrationTest { for (int i = 0; i < 9; i++) { mvc.perform(post("/{tenant}/controller/v1/4711/deploymentBase/" + actionId + "/feedback", - tenantAware.getCurrentTenant()).header(X_FORWARDED_FOR, "10.0.0.1") + AccessContext.tenant()).header(X_FORWARDED_FOR, "10.0.0.1") .content(feedback).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/JsonBuilder.java b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/JsonBuilder.java index e1129bf7d..c96a62def 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/JsonBuilder.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/JsonBuilder.java @@ -9,24 +9,13 @@ */ package org.eclipse.hawkbit.ddi.rest.resource; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.List; import java.util.Map; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; -import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; -import org.eclipse.hawkbit.repository.model.Target; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import org.springframework.util.CollectionUtils; /** * Builder class for building certain json strings. diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/AuthenticationFilters.java b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/AuthenticationFilters.java index dec327c45..bbc03811d 100644 --- a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/AuthenticationFilters.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/AuthenticationFilters.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.security.controller; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import java.util.Map; @@ -21,14 +22,13 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.eclipse.hawkbit.security.DdiSecurityProperties; -import org.eclipse.hawkbit.util.UrlUtils; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.util.AntPathMatcher; import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.web.util.UriUtils; /** * An abstraction for all controller based security to parse the e.g. the tenant name from the URL and the controller ID from the URL to do @@ -119,8 +119,9 @@ public class AuthenticationFilters { authenticator.log().debug("retrieving principal from URI request {}", requestURI); final Map extractUriTemplateVariables = pathExtractor .extractUriTemplateVariables(request.getContextPath() + CONTROLLER_REQUEST_ANT_PATTERN, requestURI); - final String controllerId = UrlUtils.decodeUriValue(extractUriTemplateVariables.get(CONTROLLER_ID_PLACE_HOLDER)); - final String tenant = UrlUtils.decodeUriValue(extractUriTemplateVariables.get(TENANT_PLACE_HOLDER)); + final String controllerId = UriUtils.decode(extractUriTemplateVariables.get(CONTROLLER_ID_PLACE_HOLDER), + StandardCharsets.UTF_8); + final String tenant = UriUtils.decode(extractUriTemplateVariables.get(TENANT_PLACE_HOLDER), StandardCharsets.UTF_8); authenticator.log().trace("Parsed tenant {} and controllerId {} from path request {}", tenant, controllerId, requestURI); return createTenantSecurityTokenVariables(request, tenant, controllerId); } else { @@ -147,8 +148,8 @@ public class AuthenticationFilters { // source ip matches the given pattern -> authenticated return true; } else { - authenticator.log().debug( - "The remote source IP address {} is not in the list of trusted IP addresses {}", remoteAddress, authorizedSourceIps); + authenticator.log().debug("The remote source IP address {} is not in the list of trusted IP addresses {}", + remoteAddress, authorizedSourceIps); return false; } } 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 ec3f78603..86b1d7fff 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 @@ -9,16 +9,15 @@ */ package org.eclipse.hawkbit.security.controller; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; + 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; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; +import org.eclipse.hawkbit.auth.SpRole; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; import org.slf4j.Logger; import org.springframework.security.authentication.AbstractAuthenticationToken; @@ -32,10 +31,10 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; public interface Authenticator { /** - * If the authentication mechanism is not enabled for the tenant - it just returns null. - * If the authentication mechanism is supported, the filter extracts from the security token the related credentials, + * If the auth mechanism is not enabled for the tenant - it just returns null. + * If the auth mechanism is supported, the filter extracts from the security token the related credentials, * validate them (do authenticate the caller). - * If validation / authentication is successful returns an authenticated authentication object. Otherwise, + * If validation / auth is successful returns an authenticated auth object. Otherwise, * throws BadCredentialsException. * * @param controllerSecurityToken the securityToken @@ -47,23 +46,10 @@ public interface Authenticator { abstract class AbstractAuthenticator implements Authenticator { - protected final TenantConfigurationManagement tenantConfigurationManagement; - protected final TenantAware tenantAware; - protected final SystemSecurityContext systemSecurityContext; - private final Callable isEnabledGetter; - - protected AbstractAuthenticator( - final TenantConfigurationManagement tenantConfigurationManagement, - final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) { - this.tenantConfigurationManagement = tenantConfigurationManagement; - this.tenantAware = tenantAware; - this.systemSecurityContext = systemSecurityContext; - isEnabledGetter = () -> systemSecurityContext.runAsSystem( - () -> tenantConfigurationManagement.getConfigurationValue(getTenantConfigurationKey(), Boolean.class).getValue()); - } - protected boolean isEnabled(final ControllerSecurityToken securityToken) { - return tenantAware.runAsTenant(securityToken.getTenant(), isEnabledGetter); + return asSystemAsTenant( + securityToken.getTenant(), + () -> TenantConfigHelper.getAsSystem(getTenantConfigurationKey(), Boolean.class)); } protected abstract String getTenantConfigurationKey(); diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/DdiSecurityProperties.java similarity index 87% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java rename to hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/DdiSecurityProperties.java index 25f9fe3ed..675b05033 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/DdiSecurityProperties.java @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.security; +package org.eclipse.hawkbit.security.controller; import java.util.List; @@ -56,7 +56,7 @@ public class DdiSecurityProperties { private String sslIssuerHashHeader = "X-Ssl-Issuer-Hash-%d"; /** * List of trusted (reverse proxy) IP addresses for performing DDI - * client certificate authentication. + * client certificate auth. */ private List trustedIPs; } @@ -71,25 +71,25 @@ public class DdiSecurityProperties { private final Gatewaytoken gatewaytoken = new Gatewaytoken(); /** - * Target token authentication. Tokens are defined per target. + * Target token auth. Tokens are defined per target. */ @Data public static class Targettoken { /** - * Set to true to enable target token authentication. + * Set to true to enable target token auth. */ private boolean enabled = false; } /** - * Gateway token authentication. Tokens are defined per tenant. Use with care! + * Gateway token auth. Tokens are defined per tenant. Use with care! */ @Data public static class Gatewaytoken { /** - * Gateway token based authentication enabled. + * Gateway token based auth enabled. */ private boolean enabled = false; 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 d11508cdc..7733f9e7f 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,16 +9,12 @@ */ package org.eclipse.hawkbit.security.controller; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; 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; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.slf4j.Logger; import org.springframework.security.core.Authentication; @@ -35,22 +31,6 @@ 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 Callable gatewaySecurityTokenKeyGetter; - - public GatewayTokenAuthenticator( - final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, - final SystemSecurityContext systemSecurityContext) { - super(tenantConfigurationManagement, tenantAware, systemSecurityContext); - gatewaySecurityTokenKeyGetter = () -> { - log.trace("retrieving configuration value for configuration key {}", AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY); - - return systemSecurityContext - .runAsSystem(() -> tenantConfigurationManagement - .getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class) - .getValue()); - }; - } - @Override public Authentication authenticate(final ControllerSecurityToken controllerSecurityToken) { final String authHeader = controllerSecurityToken.getHeader(ControllerSecurityToken.AUTHORIZATION_HEADER); @@ -63,7 +43,7 @@ public class GatewayTokenAuthenticator extends Authenticator.AbstractAuthenticat } if (!isEnabled(controllerSecurityToken)) { - log.debug("The gateway token authentication is disabled"); + log.debug("The gateway token auth is disabled"); return null; } @@ -71,8 +51,14 @@ 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(), gatewaySecurityTokenKeyGetter)) - ? authenticatedController(controllerSecurityToken.getTenant(), controllerSecurityToken.getControllerId()) : null; + return presentedToken.equals(asSystemAsTenant( + controllerSecurityToken.getTenant(), + () -> { + log.trace("retrieving configuration value for configuration key {}", AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY); + return TenantConfigHelper.getAsSystem(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class); + })) + ? authenticatedController(controllerSecurityToken.getTenant(), controllerSecurityToken.getControllerId()) + : null; } @Override 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 61b757558..77fc63633 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 @@ -9,14 +9,14 @@ */ package org.eclipse.hawkbit.security.controller; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; +import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_HEADER_AUTHORITY_NAME; + import java.util.Arrays; import java.util.List; -import java.util.concurrent.Callable; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,7 +29,7 @@ import org.springframework.security.core.Authentication; @Slf4j public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthenticator { - private static final Logger LOG_SECURITY_AUTH = LoggerFactory.getLogger("server-security.authentication"); + private static final Logger LOG_SECURITY_AUTH = LoggerFactory.getLogger("server-security.auth"); // Example Headers with Cert Information // Clientip: 217.24.201.180 @@ -48,18 +48,9 @@ public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthentic // header exists multiple times in the request for all trusted chains. private final String sslIssuerHashBasicHeader; - private final Callable sslIssuerNameConfigGetter; - - public SecurityHeaderAuthenticator( - final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, - final SystemSecurityContext systemSecurityContext, - final String caCommonNameHeader, final String caAuthorityNameHeader) { - super(tenantConfigurationManagement, tenantAware, systemSecurityContext); + public SecurityHeaderAuthenticator(final String caCommonNameHeader, final String caAuthorityNameHeader) { this.caCommonNameHeader = caCommonNameHeader; this.sslIssuerHashBasicHeader = caAuthorityNameHeader; - sslIssuerNameConfigGetter = () -> systemSecurityContext.runAsSystem( - () -> tenantConfigurationManagement.getConfigurationValue( - TenantConfigurationKey.AUTHENTICATION_HEADER_AUTHORITY_NAME, String.class).getValue()); } @Override @@ -76,13 +67,15 @@ public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthentic } if (!isEnabled(controllerSecurityToken)) { - log.debug("The gateway header authentication is disabled"); + log.debug("The gateway header auth is disabled"); return null; } final String sslIssuerHashValue = getIssuerHashHeader( controllerSecurityToken, - tenantAware.runAsTenant(controllerSecurityToken.getTenant(), sslIssuerNameConfigGetter)); + asSystemAsTenant( + controllerSecurityToken.getTenant(), + () -> TenantConfigHelper.getAsSystem(AUTHENTICATION_HEADER_AUTHORITY_NAME, String.class))); if (sslIssuerHashValue == null) { log.debug("The request contains the 'common name' header but trusted hash is not found"); return null; @@ -115,7 +108,8 @@ public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthentic // iterate over the headers until we get a null header. String foundHash; - for (int iHeader = 1; (foundHash = controllerSecurityToken.getHeader(String.format(sslIssuerHashBasicHeader, iHeader))) != null; iHeader++) { + for (int iHeader = 1; (foundHash = controllerSecurityToken.getHeader( + String.format(sslIssuerHashBasicHeader, iHeader))) != null; iHeader++) { if (knownHashes.contains(foundHash.toLowerCase())) { if (log.isTraceEnabled()) { log.trace("Found matching ssl issuer hash at position {}", iHeader); diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticator.java b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticator.java index d4162f3d6..fe11f37d0 100644 --- a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticator.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticator.java @@ -9,11 +9,10 @@ */ package org.eclipse.hawkbit.security.controller; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; + import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.ControllerManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.slf4j.Logger; import org.springframework.security.core.Authentication; @@ -32,11 +31,7 @@ public class SecurityTokenAuthenticator extends Authenticator.AbstractAuthentica private final ControllerManagement controllerManagement; - public SecurityTokenAuthenticator( - final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, - final SystemSecurityContext systemSecurityContext, - final ControllerManagement controllerManagement) { - super(tenantConfigurationManagement, tenantAware, systemSecurityContext); + public SecurityTokenAuthenticator(final ControllerManagement controllerManagement) { this.controllerManagement = controllerManagement; } @@ -52,21 +47,20 @@ public class SecurityTokenAuthenticator extends Authenticator.AbstractAuthentica } if (!isEnabled(controllerSecurityToken)) { - log.debug("The target security token authentication is disabled"); + log.debug("The target security token auth is disabled"); return null; } log.debug("Found 'authorization' header starting with '{}'", TARGET_SECURITY_TOKEN_AUTH_SCHEME); final String presentedToken = authHeader.substring(OFFSET_TARGET_TOKEN); - return systemSecurityContext.runAsSystemAsTenant(() -> controllerSecurityToken.getTargetId() != null + final String tenant = controllerSecurityToken.getTenant(); + return asSystemAsTenant(tenant, () -> controllerSecurityToken.getTargetId() != null ? controllerManagement.find(controllerSecurityToken.getTargetId()) - : controllerManagement.findByControllerId(controllerSecurityToken.getControllerId()), - controllerSecurityToken.getTenant()) + : controllerManagement.findByControllerId(controllerSecurityToken.getControllerId())) // validate if the presented token is the same as the one set for the target - .filter(target -> presentedToken.equals( - systemSecurityContext.runAsSystemAsTenant(target::getSecurityToken, controllerSecurityToken.getTenant()))) - .map(target -> authenticatedController(controllerSecurityToken.getTenant(), target.getControllerId())) + .filter(target -> presentedToken.equals(asSystemAsTenant(tenant, target::getSecurityToken))) + .map(target -> authenticatedController(tenant, target.getControllerId())) .orElse(null); } diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticatorTest.java b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticatorTest.java index 346f50eb6..03e0a1fcd 100644 --- a/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticatorTest.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticatorTest.java @@ -16,10 +16,8 @@ import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationPrope import static org.mockito.Mockito.when; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -28,7 +26,7 @@ import org.mockito.junit.jupiter.MockitoExtension; /** * Feature: Unit Tests - Security
- * Story: Gateway token authentication + * Story: Gateway token auth */ @ExtendWith(MockitoExtension.class) class GatewayTokenAuthenticatorTest { @@ -48,17 +46,15 @@ class GatewayTokenAuthenticatorTest { @Mock private TenantConfigurationManagement tenantConfigurationManagementMock; - @Mock - private UserAuthoritiesResolver authoritiesResolver; @BeforeEach void before() { - final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver); - authenticator = new GatewayTokenAuthenticator(tenantConfigurationManagementMock, tenantAware, new SystemSecurityContext(tenantAware)); + TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagementMock); + authenticator = new GatewayTokenAuthenticator(); } /** - * Tests successful authentication with gateway token + * Tests successful auth with gateway token */ @Test void testWithGwToken() { @@ -74,7 +70,7 @@ class GatewayTokenAuthenticatorTest { } /** - * Tests that if gateway token doesn't match, the authentication fails + * Tests that if gateway token doesn't match, the auth fails */ @Test void testWithBadGwToken() { @@ -88,7 +84,7 @@ class GatewayTokenAuthenticatorTest { } /** - * Tests that if gateway token miss, the authentication fails + * Tests that if gateway token miss, the auth fails */ @Test void testWithoutGwToken() { @@ -96,7 +92,7 @@ class GatewayTokenAuthenticatorTest { } /** - * Tests that if disabled, the authentication fails + * Tests that if disabled, the auth fails */ @Test void testWithGwTokenButDisabled() { diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticatorTest.java b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticatorTest.java index 73e4190f3..b46690b14 100644 --- a/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticatorTest.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticatorTest.java @@ -15,10 +15,8 @@ import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationPrope import static org.mockito.Mockito.when; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -57,20 +55,15 @@ class SecurityHeaderAuthenticatorTest { @Mock private TenantConfigurationManagement tenantConfigurationManagementMock; - @Mock - private UserAuthoritiesResolver authoritiesResolver; @BeforeEach void before() { - final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver); - authenticator = new SecurityHeaderAuthenticator( - tenantConfigurationManagementMock, tenantAware, - new SystemSecurityContext(tenantAware), CA_COMMON_NAME, "X-Ssl-Issuer-Hash-%d" - ); + TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagementMock); + authenticator = new SecurityHeaderAuthenticator(CA_COMMON_NAME, "X-Ssl-Issuer-Hash-%d"); } /** - * Tests successful authentication with multiple a single hashes + * Tests successful auth with multiple a single hashes */ @Test void testWithSingleKnownHash() { @@ -86,7 +79,7 @@ class SecurityHeaderAuthenticatorTest { } /** - * Tests successful authentication with multiple hashes + * Tests successful auth with multiple hashes */ @Test void testWithMultipleKnownHashes() { @@ -107,7 +100,7 @@ class SecurityHeaderAuthenticatorTest { } /** - * Tests that if the hash is unknown, the authentication fails + * Tests that if the hash is unknown, the auth fails */ @Test void testWithUnknownHash() { @@ -121,7 +114,7 @@ class SecurityHeaderAuthenticatorTest { } /** - * Tests that if CN doesn't match the CN in the security token, the authentication fails + * Tests that if CN doesn't match the CN in the security token, the auth fails */ @Test void testWithNonMatchingCN() { @@ -133,7 +126,7 @@ class SecurityHeaderAuthenticatorTest { } /** - * Tests that if the hash miss, the authentication fails + * Tests that if the hash miss, the auth fails */ @Test void testWithoutHash() { @@ -141,7 +134,7 @@ class SecurityHeaderAuthenticatorTest { } /** - * Tests that if disabled, the authentication fails + * Tests that if disabled, the auth fails */ @Test void testWithSingleKnownHashButDisabled() { diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticatorTest.java b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticatorTest.java index bce2cea42..50e9acf06 100644 --- a/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticatorTest.java +++ b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticatorTest.java @@ -17,11 +17,9 @@ import java.util.Optional; import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -31,7 +29,7 @@ import org.mockito.junit.jupiter.MockitoExtension; /** * Feature: Unit Tests - Security
- * Story: Gateway token authentication + * Story: Gateway token auth */ @ExtendWith(MockitoExtension.class) class SecurityTokenAuthenticatorTest { @@ -51,19 +49,15 @@ class SecurityTokenAuthenticatorTest { private TenantConfigurationManagement tenantConfigurationManagementMock; @Mock private ControllerManagement controllerManagementMock; - @Mock - private UserAuthoritiesResolver authoritiesResolver; @BeforeEach void before() { - final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver); - authenticator = new SecurityTokenAuthenticator( - tenantConfigurationManagementMock, tenantAware, - new SystemSecurityContext(tenantAware), controllerManagementMock); + TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagementMock); + authenticator = new SecurityTokenAuthenticator(controllerManagementMock); } /** - * Tests successful authentication with gateway token + * Tests successful auth with gateway token */ @Test void testWithSecToken() { @@ -82,7 +76,7 @@ class SecurityTokenAuthenticatorTest { } /** - * Tests that if gateway token doesn't match, the authentication fails + * Tests that if gateway token doesn't match, the auth fails */ @Test void testWithBadSecToken() { @@ -94,7 +88,7 @@ class SecurityTokenAuthenticatorTest { } /** - * Tests that if gateway token miss, the authentication fails + * Tests that if gateway token miss, the auth fails */ @Test void testWithoutSecToken() { @@ -102,7 +96,7 @@ class SecurityTokenAuthenticatorTest { } /** - * Tests that if disabled, the authentication fails + * Tests that if disabled, the auth fails */ @Test void testWithSecTokenButDisabled() { diff --git a/hawkbit-ddi/hawkbit-ddi-server/src/main/resources/application.properties b/hawkbit-ddi/hawkbit-ddi-server/src/main/resources/application.properties index dc6cd3340..52b0e8819 100644 --- a/hawkbit-ddi/hawkbit-ddi-server/src/main/resources/application.properties +++ b/hawkbit-ddi/hawkbit-ddi-server/src/main/resources/application.properties @@ -30,7 +30,7 @@ server.servlet.encoding.charset=UTF-8 server.servlet.encoding.enabled=true server.servlet.encoding.force=true -# DDI authentication configuration +# DDI auth configuration hawkbit.server.ddi.security.authentication.targettoken.enabled=false hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false diff --git a/hawkbit-ddi/hawkbit-ddi-server/src/test/java/org/eclipse/hawkbit/app/ddi/PreAuthorizeEnabledTest.java b/hawkbit-ddi/hawkbit-ddi-server/src/test/java/org/eclipse/hawkbit/app/ddi/PreAuthorizeEnabledTest.java index 0c298134e..ffb724cd6 100644 --- a/hawkbit-ddi/hawkbit-ddi-server/src/test/java/org/eclipse/hawkbit/app/ddi/PreAuthorizeEnabledTest.java +++ b/hawkbit-ddi/hawkbit-ddi-server/src/test/java/org/eclipse/hawkbit/app/ddi/PreAuthorizeEnabledTest.java @@ -12,8 +12,8 @@ package org.eclipse.hawkbit.app.ddi; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/ControllerDownloadSecurityConfiguration.java b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/ControllerDownloadSecurityConfiguration.java index d64b72c5f..4e8943cab 100644 --- a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/ControllerDownloadSecurityConfiguration.java +++ b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/ControllerDownloadSecurityConfiguration.java @@ -12,20 +12,17 @@ package org.eclipse.hawkbit.autoconfigure.ddi; import java.util.List; import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.context.Mdc; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; import org.eclipse.hawkbit.repository.ControllerManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.rest.SecurityManagedConfiguration; import org.eclipse.hawkbit.rest.security.DosFilter; -import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.security.MdcHandler; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.security.controller.AuthenticationFilters; +import org.eclipse.hawkbit.security.controller.DdiSecurityProperties; import org.eclipse.hawkbit.security.controller.GatewayTokenAuthenticator; import org.eclipse.hawkbit.security.controller.SecurityHeaderAuthenticator; import org.eclipse.hawkbit.security.controller.SecurityTokenAuthenticator; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; @@ -50,23 +47,15 @@ class ControllerDownloadSecurityConfiguration { DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/*"; private final ControllerManagement controllerManagement; - private final TenantConfigurationManagement tenantConfigurationManagement; - private final TenantAware tenantAware; private final DdiSecurityProperties ddiSecurityConfiguration; private final HawkbitSecurityProperties securityProperties; - private final SystemSecurityContext systemSecurityContext; ControllerDownloadSecurityConfiguration( final ControllerManagement controllerManagement, - final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, - final DdiSecurityProperties ddiSecurityConfiguration, - final HawkbitSecurityProperties securityProperties, final SystemSecurityContext systemSecurityContext) { + final DdiSecurityProperties ddiSecurityConfiguration, final HawkbitSecurityProperties securityProperties) { this.controllerManagement = controllerManagement; - this.tenantConfigurationManagement = tenantConfigurationManagement; - this.tenantAware = tenantAware; this.ddiSecurityConfiguration = ddiSecurityConfiguration; this.securityProperties = securityProperties; - this.systemSecurityContext = systemSecurityContext; } /** @@ -95,17 +84,13 @@ class ControllerDownloadSecurityConfiguration { .csrf(AbstractHttpConfigurer::disable) .addFilterBefore(new AuthenticationFilters.SecurityHeaderAuthenticationFilter( new SecurityHeaderAuthenticator( - tenantConfigurationManagement, tenantAware, systemSecurityContext, ddiSecurityConfiguration.getRp().getCnHeader(), ddiSecurityConfiguration.getRp().getSslIssuerHashHeader()), ddiSecurityConfiguration), AuthorizationFilter.class) .addFilterBefore(new AuthenticationFilters.SecurityTokenAuthenticationFilter( - new SecurityTokenAuthenticator( - tenantConfigurationManagement, tenantAware, systemSecurityContext, - controllerManagement), + new SecurityTokenAuthenticator(controllerManagement), ddiSecurityConfiguration), AuthorizationFilter.class) .addFilterBefore(new AuthenticationFilters.GatewayTokenAuthenticationFilter( - new GatewayTokenAuthenticator( - tenantConfigurationManagement, tenantAware, systemSecurityContext), + new GatewayTokenAuthenticator(), ddiSecurityConfiguration), AuthorizationFilter.class) .exceptionHandling(configurer -> configurer.authenticationEntryPoint( (request, response, authException) -> response.setStatus(HttpStatus.UNAUTHORIZED.value()))) @@ -115,7 +100,7 @@ class ControllerDownloadSecurityConfiguration { http.redirectToHttps(Customizer.withDefaults()); } - MdcHandler.Filter.addMdcFilter(http); + Mdc.Filter.addMdcFilter(http); return http.build(); } diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/ControllerSecurityConfiguration.java b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/ControllerSecurityConfiguration.java index 3375c505b..09cfb1829 100644 --- a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/ControllerSecurityConfiguration.java +++ b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/ControllerSecurityConfiguration.java @@ -12,20 +12,17 @@ package org.eclipse.hawkbit.autoconfigure.ddi; import java.util.List; import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.context.Mdc; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; import org.eclipse.hawkbit.repository.ControllerManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.rest.SecurityManagedConfiguration; import org.eclipse.hawkbit.rest.security.DosFilter; -import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.security.MdcHandler; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.security.controller.AuthenticationFilters; +import org.eclipse.hawkbit.security.controller.DdiSecurityProperties; import org.eclipse.hawkbit.security.controller.GatewayTokenAuthenticator; import org.eclipse.hawkbit.security.controller.SecurityHeaderAuthenticator; import org.eclipse.hawkbit.security.controller.SecurityTokenAuthenticator; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -52,23 +49,16 @@ class ControllerSecurityConfiguration { private static final String[] DDI_ANT_MATCHERS = { DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/**" }; private final ControllerManagement controllerManagement; - private final TenantConfigurationManagement tenantConfigurationManagement; - private final TenantAware tenantAware; private final DdiSecurityProperties ddiSecurityConfiguration; private final HawkbitSecurityProperties securityProperties; - private final SystemSecurityContext systemSecurityContext; @Autowired - ControllerSecurityConfiguration(final ControllerManagement controllerManagement, - final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, - final DdiSecurityProperties ddiSecurityConfiguration, - final HawkbitSecurityProperties securityProperties, final SystemSecurityContext systemSecurityContext) { + ControllerSecurityConfiguration( + final ControllerManagement controllerManagement, final DdiSecurityProperties ddiSecurityConfiguration, + final HawkbitSecurityProperties securityProperties) { this.controllerManagement = controllerManagement; - this.tenantConfigurationManagement = tenantConfigurationManagement; - this.tenantAware = tenantAware; this.ddiSecurityConfiguration = ddiSecurityConfiguration; this.securityProperties = securityProperties; - this.systemSecurityContext = systemSecurityContext; } /** @@ -89,7 +79,6 @@ class ControllerSecurityConfiguration { return filterRegBean; } - @Bean @Order(301) protected SecurityFilterChain filterChainDDI( @@ -100,24 +89,23 @@ class ControllerSecurityConfiguration { .authorizeHttpRequests(amrmRegistry -> amrmRegistry.anyRequest().authenticated()) .anonymous(AbstractHttpConfigurer::disable) .csrf(AbstractHttpConfigurer::disable) - .addFilterBefore(new AuthenticationFilters.SecurityHeaderAuthenticationFilter( - new SecurityHeaderAuthenticator( - tenantConfigurationManagement, tenantAware, - systemSecurityContext, ddiSecurityConfiguration.getRp().getCnHeader(), ddiSecurityConfiguration.getRp().getSslIssuerHashHeader() - ), ddiSecurityConfiguration), AuthorizationFilter.class) - .addFilterBefore(new AuthenticationFilters.SecurityTokenAuthenticationFilter( - new SecurityTokenAuthenticator( - tenantConfigurationManagement, tenantAware, - systemSecurityContext, controllerManagement), ddiSecurityConfiguration), AuthorizationFilter.class) - .addFilterBefore(new AuthenticationFilters.GatewayTokenAuthenticationFilter( - new GatewayTokenAuthenticator( - tenantConfigurationManagement, tenantAware, - systemSecurityContext), ddiSecurityConfiguration), AuthorizationFilter.class) + .addFilterBefore( + new AuthenticationFilters.SecurityHeaderAuthenticationFilter( + new SecurityHeaderAuthenticator( + ddiSecurityConfiguration.getRp().getCnHeader(), + ddiSecurityConfiguration.getRp().getSslIssuerHashHeader()), ddiSecurityConfiguration), + AuthorizationFilter.class) + .addFilterBefore( + new AuthenticationFilters.SecurityTokenAuthenticationFilter( + new SecurityTokenAuthenticator(controllerManagement), ddiSecurityConfiguration), + AuthorizationFilter.class) + .addFilterBefore( + new AuthenticationFilters.GatewayTokenAuthenticationFilter(new GatewayTokenAuthenticator(), ddiSecurityConfiguration), + AuthorizationFilter.class) .exceptionHandling(configurer -> configurer.authenticationEntryPoint( (request, response, authException) -> response.setStatus(HttpStatus.UNAUTHORIZED.value()))) .sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); - if (securityProperties.getCors().isEnabled() && !disableCorsForDdiApi) { http.cors(configurer -> configurer.configurationSource(securityProperties.getCors().toCorsConfigurationSource())); } @@ -126,7 +114,7 @@ class ControllerSecurityConfiguration { http.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure()); } - MdcHandler.Filter.addMdcFilter(http); + Mdc.Filter.addMdcFilter(http); return http.build(); } diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/DdiApiAutoConfiguration.java b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/DdiApiAutoConfiguration.java index d963ad8aa..6757c0438 100644 --- a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/DdiApiAutoConfiguration.java +++ b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/DdiApiAutoConfiguration.java @@ -10,7 +10,7 @@ package org.eclipse.hawkbit.autoconfigure.ddi; import org.eclipse.hawkbit.ddi.rest.resource.DdiApiConfiguration; -import org.eclipse.hawkbit.security.DdiSecurityProperties; +import org.eclipse.hawkbit.security.controller.DdiSecurityProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/pom.xml b/hawkbit-dmf/hawkbit-dmf-amqp/pom.xml index bb0214470..958363ba2 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/pom.xml +++ b/hawkbit-dmf/hawkbit-dmf-amqp/pom.xml @@ -32,11 +32,6 @@ hawkbit-core ${project.version}
- - org.eclipse.hawkbit - hawkbit-security-core - ${project.version} - org.eclipse.hawkbit hawkbit-dmf-api diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java index 75d81d05a..e64f71468 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java @@ -9,6 +9,7 @@ */ package org.eclipse.hawkbit.amqp; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT; import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED; @@ -51,7 +52,6 @@ import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent; import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent; import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent; @@ -64,6 +64,7 @@ import org.eclipse.hawkbit.repository.event.remote.service.MultiActionCancelServ import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistributionSetServiceEvent; import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent; import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.ActionProperties; import org.eclipse.hawkbit.repository.model.Artifact; @@ -71,8 +72,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TenantMetaData; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.utils.IpUtil; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageBuilder; import org.springframework.amqp.core.MessageProperties; @@ -94,43 +94,36 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { private final ArtifactUrlResolver artifactUrlHandler; private final AmqpMessageSenderService amqpSenderService; - private final SystemSecurityContext systemSecurityContext; private final SystemManagement systemManagement; private final TargetManagement targetManagement; private final SoftwareModuleManagement softwareModuleManagement; private final DistributionSetManagement distributionSetManagement; private final DeploymentManagement deploymentManagement; - private final TenantConfigurationManagement tenantConfigurationManagement; private final RepositoryProperties repositoryProperties; @SuppressWarnings("java:S107") protected AmqpMessageDispatcherService( final RabbitTemplate rabbitTemplate, final AmqpMessageSenderService amqpSenderService, final ArtifactUrlResolver artifactUrlHandler, - final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement, + final SystemManagement systemManagement, final TargetManagement targetManagement, final SoftwareModuleManagement softwareModuleManagement, final DistributionSetManagement distributionSetManagement, final DeploymentManagement deploymentManagement, - final TenantConfigurationManagement tenantConfigurationManagement, final RepositoryProperties repositoryProperties) { super(rabbitTemplate); this.artifactUrlHandler = artifactUrlHandler; this.amqpSenderService = amqpSenderService; - this.systemSecurityContext = systemSecurityContext; this.systemManagement = systemManagement; this.targetManagement = targetManagement; this.softwareModuleManagement = softwareModuleManagement; this.distributionSetManagement = distributionSetManagement; this.deploymentManagement = deploymentManagement; - this.tenantConfigurationManagement = tenantConfigurationManagement; this.repositoryProperties = repositoryProperties; } public boolean isBatchAssignmentsEnabled() { - return systemSecurityContext.runAsSystem(() -> - tenantConfigurationManagement - .getConfigurationValue(BATCH_ASSIGNMENTS_ENABLED, Boolean.class).getValue()); + return TenantConfigHelper.getAsSystem(BATCH_ASSIGNMENTS_ENABLED, Boolean.class); } /** @@ -184,9 +177,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { protected DmfDownloadAndUpdateRequest createDownloadAndUpdateRequest( final Target target, final Long actionId, final Map> softwareModules) { return new DmfDownloadAndUpdateRequest( - actionId, - systemSecurityContext.runAsSystem(target::getSecurityToken), - convertToAmqpSoftwareModules(target, softwareModules)); + actionId, asSystem(target::getSecurityToken), convertToAmqpSoftwareModules(target, softwareModules)); } /** @@ -227,7 +218,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { protected void sendPingResponseToDmfReceiver(final Message ping, final String tenant, final String virtualHost) { final Message message = MessageBuilder - .withBody(String.valueOf(System.currentTimeMillis()).getBytes()) + .withBody(String.valueOf(java.lang.System.currentTimeMillis()).getBytes()) .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN) .setCorrelationId(ping.getMessageProperties().getCorrelationId()) .setHeader(MessageHeaderKey.TYPE, MessageType.PING_RESPONSE) @@ -251,16 +242,9 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { amqpSenderService.sendMessage(message, address); } - protected DmfTarget convertToDmfTarget(final Target target, final Long actionId) { - return new DmfTarget(actionId, target.getControllerId(), systemSecurityContext.runAsSystem(target::getSecurityToken)); - } - protected DmfConfirmRequest createConfirmRequest( final Target target, final Long actionId, final Map> softwareModules) { - return new DmfConfirmRequest( - actionId, - systemSecurityContext.runAsSystem(target::getSecurityToken), - convertToAmqpSoftwareModules(target, softwareModules)); + return new DmfConfirmRequest(actionId, asSystem(target::getSecurityToken), convertToAmqpSoftwareModules(target, softwareModules)); } void sendMultiActionRequestToTarget( @@ -580,13 +564,14 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { final Map> modules) { final List dmfTargets = targets.stream() .filter(target -> IpUtil.isAmqpUri(IpUtil.addressToUri(target.getAddress()))) - .map(t -> convertToDmfTarget(t, actions.get(t.getControllerId()).getId())) + // as system - the security token is sent to DMF receiver + .map(t -> new DmfTarget(actions.get(t.getControllerId()).getId(), t.getControllerId(), asSystem(t::getSecurityToken))) .toList(); // due to the fact that all targets in a batch use the same set of software modules we don't generate target-specific urls final Target firstTarget = targets.get(0); final DmfBatchDownloadAndUpdateRequest batchRequest = new DmfBatchDownloadAndUpdateRequest( - System.currentTimeMillis(), + java.lang.System.currentTimeMillis(), dmfTargets, Optional.ofNullable(modules) .map(Map::entrySet) @@ -594,7 +579,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { .map(stream -> stream.map(entry -> convertToAmqpSoftwareModule(firstTarget, entry)).toList()) .orElse(null)); - // we use only the first action when constructing message as Tenant and action type are the same + // we use only the first action when constructing message as AccessContext and action type are the same // since all actions have the same trigger final ActionProperties firstAction = actions.values().iterator().next(); final Message message = getMessageConverter().toMessage( diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java index 38818c228..af15d676e 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java @@ -10,9 +10,7 @@ package org.eclipse.hawkbit.amqp; import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT; -import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED; -import java.io.Serializable; import java.net.URI; import java.util.ArrayList; import java.util.Collections; @@ -28,6 +26,7 @@ import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.audit.AuditLog; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; import org.eclipse.hawkbit.dmf.amqp.api.MessageType; @@ -37,14 +36,13 @@ import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate; import org.eclipse.hawkbit.dmf.json.model.DmfAutoConfirmation; import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing; import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; -import org.eclipse.hawkbit.im.authentication.SpRole; import org.eclipse.hawkbit.repository.ConfirmationManagement; import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.RepositoryConstants; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate; import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate.ActionStatusCreateBuilder; @@ -53,9 +51,9 @@ import org.eclipse.hawkbit.repository.model.ActionProperties; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; +import org.eclipse.hawkbit.utils.IpUtil; import org.springframework.amqp.AmqpRejectAndDontRequeueException; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; @@ -82,30 +80,16 @@ public class AmqpMessageHandlerService extends BaseAmqpService { private final AmqpMessageDispatcherService amqpMessageDispatcherService; private final ConfirmationManagement confirmationManagement; - private final TenantConfigurationManagement tenantConfigurationManagement; - private final SystemSecurityContext systemSecurityContext; private ControllerManagement controllerManagement; - /** - * Constructor. - * - * @param rabbitTemplate for converting messages - * @param amqpMessageDispatcherService to sending events to DMF client - * @param controllerManagement for target repo access - * @param systemSecurityContext the system Security Context - * @param tenantConfigurationManagement the tenant configuration Management - * @param confirmationManagement the confirmation management - */ public AmqpMessageHandlerService( final RabbitTemplate rabbitTemplate, final AmqpMessageDispatcherService amqpMessageDispatcherService, - final ControllerManagement controllerManagement, final SystemSecurityContext systemSecurityContext, - final TenantConfigurationManagement tenantConfigurationManagement, final ConfirmationManagement confirmationManagement) { + final ControllerManagement controllerManagement, + final ConfirmationManagement confirmationManagement) { super(rabbitTemplate); this.amqpMessageDispatcherService = amqpMessageDispatcherService; this.controllerManagement = controllerManagement; - this.systemSecurityContext = systemSecurityContext; - this.tenantConfigurationManagement = tenantConfigurationManagement; this.confirmationManagement = confirmationManagement; } @@ -331,7 +315,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService { } private void sendUpdateCommandToTarget(final Target target) { - if (isMultiAssignmentsEnabled()) { + if (TenantConfigHelper.getAsSystem(TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, Boolean.class)) { sendCurrentActionsAsMultiActionToTarget(target); } else { sendOldestActionToTarget(target); @@ -456,8 +440,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService { } else if (actionUpdateStatus.getActionStatus() == DmfActionStatus.DENIED) { updatedAction = confirmationManagement.denyAction(action.getId(), actionUpdateStatus.getCode(), messages); } else { - final ActionStatusCreateBuilder actionStatus = ActionStatusCreate.builder().actionId(action.getId()) - .status(status); + final ActionStatusCreateBuilder actionStatus = ActionStatusCreate.builder().actionId(action.getId()).status(status); Optional.ofNullable(actionUpdateStatus.getCode()).ifPresentOrElse( code -> { actionStatus.code(code); @@ -491,12 +474,4 @@ public class AmqpMessageHandlerService extends BaseAmqpService { return findActionWithDetails.get(); } - - private boolean isMultiAssignmentsEnabled() { - return getConfigValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class); - } - - private T getConfigValue(final String key, final Class valueType) { - return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue()); - } -} +} \ No newline at end of file diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpMessageSenderService.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpMessageSenderService.java index 433c1b41c..26fa26df0 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpMessageSenderService.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpMessageSenderService.java @@ -13,7 +13,7 @@ import java.net.URI; import java.util.UUID; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.utils.IpUtil; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.connection.CorrelationData; import org.springframework.amqp.rabbit.core.RabbitTemplate; diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DmfApiConfiguration.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DmfApiConfiguration.java index 30e29b9ae..e9665e049 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DmfApiConfiguration.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DmfApiConfiguration.java @@ -28,11 +28,9 @@ import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.FanoutExchange; @@ -150,7 +148,7 @@ public class DmfApiConfiguration { } /** - * Create the DMF API receiver queue for authentication requests called by 3rd + * Create the DMF API receiver queue for auth requests called by 3rd * party artifact storages for download authorization by devices. * * @return the receiver queue @@ -227,12 +225,10 @@ public class DmfApiConfiguration { public AmqpMessageHandlerService amqpMessageHandlerService( final RabbitTemplate rabbitTemplate, final AmqpMessageDispatcherService amqpMessageDispatcherService, - final ControllerManagement controllerManagement, final SystemSecurityContext systemSecurityContext, - final TenantConfigurationManagement tenantConfigurationManagement, + final ControllerManagement controllerManagement, final ConfirmationManagement confirmationManagement) { return new AmqpMessageHandlerService( - rabbitTemplate, amqpMessageDispatcherService, controllerManagement, - systemSecurityContext, tenantConfigurationManagement, confirmationManagement); + rabbitTemplate, amqpMessageDispatcherService, controllerManagement, confirmationManagement); } /** @@ -266,14 +262,14 @@ public class DmfApiConfiguration { AmqpMessageDispatcherService amqpMessageDispatcherService( final RabbitTemplate rabbitTemplate, final AmqpMessageSenderService amqpSenderService, final ArtifactUrlResolver artifactUrlHandler, - final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement, + final SystemManagement systemManagement, final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement, final SoftwareModuleManagement softwareModuleManagement, final DeploymentManagement deploymentManagement, - final TenantConfigurationManagement tenantConfigurationManagement, final RepositoryProperties repositoryProperties) { + final RepositoryProperties repositoryProperties) { return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler, - systemSecurityContext, systemManagement, targetManagement, softwareModuleManagement, distributionSetManagement, - deploymentManagement, tenantConfigurationManagement, repositoryProperties); + systemManagement, targetManagement, softwareModuleManagement, distributionSetManagement, + deploymentManagement, repositoryProperties); } private static Map getTTLMaxArgsAuthenticationQueue() { diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java index 62d42373a..41a9bea23 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java @@ -52,7 +52,7 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TenantMetaData; import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest; import org.eclipse.hawkbit.repository.test.util.TestdataFactory; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.utils.IpUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -116,8 +116,8 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest { when(systemManagement.getTenantMetadataWithoutDetails()).thenReturn(tenantMetaData); amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService, - artifactUrlHandlerMock, systemSecurityContext, systemManagement, targetManagement, - softwareModuleManagement, distributionSetManagement, deploymentManagement, tenantConfigurationManagement, repositoryProperties); + artifactUrlHandlerMock, systemManagement, targetManagement, + softwareModuleManagement, distributionSetManagement, deploymentManagement, repositoryProperties); } diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java index bf97431d4..4a9168e5f 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java @@ -21,7 +21,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.lang.reflect.Field; import java.net.URI; import java.util.Map; import java.util.Optional; @@ -40,16 +39,12 @@ import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; -import org.eclipse.hawkbit.repository.SecurityTokenGeneratorHolder; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.ActionProperties; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.security.SecurityTokenGenerator; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -93,8 +88,6 @@ class AmqpMessageHandlerServiceTest { private TenantConfigurationManagement tenantConfigurationManagement; @Mock private RabbitTemplate rabbitTemplate; - @Mock - private UserAuthoritiesResolver authoritiesResolver; @Captor private ArgumentCaptor> attributesCaptor; @@ -116,6 +109,7 @@ class AmqpMessageHandlerServiceTest { @BeforeEach @SuppressWarnings({ "rawtypes", "unchecked" }) void before() { + TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagement); messageConverter = new Jackson2JsonMessageConverter(); lenient().when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter); final TenantConfigurationValue multiAssignmentConfig = TenantConfigurationValue.builder().value(Boolean.FALSE) @@ -123,12 +117,8 @@ class AmqpMessageHandlerServiceTest { lenient().when(tenantConfigurationManagement.getConfigurationValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class)) .thenReturn(multiAssignmentConfig); - final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver); - final SystemSecurityContext systemSecurityContext = new SystemSecurityContext(tenantAware); - - amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock, - controllerManagementMock, systemSecurityContext, tenantConfigurationManagement, - confirmationManagementMock); + amqpMessageHandlerService = new AmqpMessageHandlerService( + rabbitTemplate, amqpMessageDispatcherServiceMock, controllerManagementMock, confirmationManagementMock); } /** @@ -442,7 +432,7 @@ class AmqpMessageHandlerServiceTest { * Test next update is provided on finished action */ @Test - void lookupNextUpdateActionAfterFinished() throws IllegalAccessException { + void lookupNextUpdateActionAfterFinished() { // Mock final Action action = createActionWithTarget(22L); @@ -655,10 +645,7 @@ class AmqpMessageHandlerServiceTest { return messageProperties; } - private Action createActionWithTarget(final Long targetId) throws IllegalAccessException { - // is needed for the creation of targets - initializeSecurityTokenGenerator(); - + private Action createActionWithTarget(final Long targetId) { // Mock final Action actionMock = mock(Action.class); final Target targetMock = mock(Target.class); @@ -673,17 +660,6 @@ class AmqpMessageHandlerServiceTest { return actionMock; } - private void initializeSecurityTokenGenerator() throws IllegalAccessException { - final SecurityTokenGeneratorHolder instance = SecurityTokenGeneratorHolder.getInstance(); - final Field[] fields = instance.getClass().getDeclaredFields(); - for (final Field field : fields) { - if (field.getType().isAssignableFrom(SecurityTokenGenerator.class)) { - field.setAccessible(true); - field.set(instance, new SecurityTokenGenerator()); - } - } - } - private MessageProperties getThingCreatedMessageProperties(final String thingId) { final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); messageProperties.setHeader(MessageHeaderKey.THING_ID, thingId); diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AbstractAmqpServiceIntegrationTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AbstractAmqpServiceIntegrationTest.java index 0b7780965..4b9161ea3 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AbstractAmqpServiceIntegrationTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AbstractAmqpServiceIntegrationTest.java @@ -51,7 +51,7 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch; import org.eclipse.hawkbit.repository.test.util.TestdataFactory; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.utils.IpUtil; import org.junit.jupiter.api.BeforeEach; import org.mockito.Mockito; import org.springframework.amqp.core.Message; @@ -93,9 +93,9 @@ abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpIntegratio } protected T waitUntilIsPresent(final Callable> callable) { - await().until(() -> SecurityContextSwitch.callAsPrivileged(() -> callable.call().isPresent())); + await().until(() -> SecurityContextSwitch.asPrivileged(() -> callable.call().isPresent())); try { - return SecurityContextSwitch.callAsPrivileged(() -> callable.call().get()); + return SecurityContextSwitch.asPrivileged(() -> callable.call().get()); } catch (final Exception e) { return null; } @@ -368,7 +368,7 @@ abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpIntegratio waitUntilIsPresent(() -> controllerManagement.findByControllerId(controllerId)); await().untilAsserted(() -> { try { - final Map controllerAttributes = SecurityContextSwitch.callAsPrivileged( + final Map controllerAttributes = SecurityContextSwitch.asPrivileged( () -> targetManagement.getControllerAttributes(controllerId)); assertThat(controllerAttributes).hasSameSizeAs(attributes); assertThat(controllerAttributes).containsAllEntriesOf(attributes); diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java index e4a5fb636..2a76dfe11 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java @@ -793,7 +793,7 @@ class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpServiceInt } private void waitUntil(final Callable callable) { - await().until(() -> SecurityContextSwitch.callAsPrivileged(callable)); + await().until(() -> SecurityContextSwitch.asPrivileged(callable)); } private void assertLatestMultiActionMessageContainsInstallMessages(final String controllerId, diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java index d29ff5246..0cd7be792 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java @@ -1231,7 +1231,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr private void assertAction(final Long actionId, final int messages, final Status... expectedActionStates) { await().untilAsserted(() -> { try { - SecurityContextSwitch.callAsPrivileged(() -> { + SecurityContextSwitch.asPrivileged(() -> { final List actionStatusList = deploymentManagement.findActionStatusByAction(actionId, PAGE).getContent(); // Check correlation ID @@ -1265,7 +1265,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr final Status... expectedActionStates) { await().untilAsserted(() -> { try { - SecurityContextSwitch.callAsPrivileged(() -> { + SecurityContextSwitch.asPrivileged(() -> { final List actionStatusList = deploymentManagement .findActionStatusByAction(actionId, PAGE).getContent(); assertThat(actionStatusList).hasSize(statusListCount); diff --git a/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/AmqpTestConfiguration.java b/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/AmqpTestConfiguration.java index 245fe0764..13e8e49ca 100644 --- a/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/AmqpTestConfiguration.java +++ b/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/AmqpTestConfiguration.java @@ -14,7 +14,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.eclipse.hawkbit.repository.helper.SystemSecurityContextHolder; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; @@ -39,11 +38,6 @@ public class AmqpTestConfiguration { return rabbitTemplate; } - @Bean - SystemSecurityContextHolder systemSecurityContextHolder() { - return SystemSecurityContextHolder.getInstance(); - } - @Bean Executor asyncExecutor() { return new DelegatingSecurityContextExecutorService(Executors.newSingleThreadExecutor()); diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtActionRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtActionRestApi.java index 3e76d9f66..f32ffffa4 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtActionRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtActionRestApi.java @@ -11,6 +11,8 @@ package org.eclipse.hawkbit.mgmt.rest.api; import static org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants.ACTION_ORDER; +import java.util.List; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.extensions.Extension; import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; @@ -32,8 +34,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; -import java.util.List; - /** * REST API providing (read-only) access to actions. */ @@ -60,7 +60,7 @@ public interface MgmtActionRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -116,7 +116,7 @@ public interface MgmtActionRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "404", description = "Target not found.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @@ -140,7 +140,7 @@ public interface MgmtActionRestApi { @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or data volume restriction applies.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "404", description = "Action not found.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @@ -160,7 +160,7 @@ public interface MgmtActionRestApi { @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or data volume restriction applies.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "406", description = "In case accept header is specified and not application/json.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java index 8c755fc5a..2d8537dab 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java @@ -76,7 +76,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -126,7 +126,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -159,7 +159,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -195,7 +195,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -226,7 +226,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -272,7 +272,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -331,7 +331,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -390,7 +390,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -448,7 +448,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -488,7 +488,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -527,7 +527,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -559,7 +559,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -593,7 +593,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully updated"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -633,7 +633,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -668,7 +668,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -709,7 +709,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -747,7 +747,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -796,7 +796,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -829,7 +829,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -861,7 +861,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -894,7 +894,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -930,7 +930,7 @@ public interface MgmtDistributionSetRestApi { @ApiResponse(responseCode = "204", description = "Successfully invalidated distribution set"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java index 6725430f1..230dcb2e6 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java @@ -64,7 +64,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -115,7 +115,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -148,7 +148,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -186,7 +186,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -227,7 +227,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -269,7 +269,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -324,7 +324,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -362,7 +362,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -404,7 +404,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully unassigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -439,7 +439,7 @@ public interface MgmtDistributionSetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully unassigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTypeRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTypeRestApi.java index a231a36dd..2b424da2c 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTypeRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTypeRestApi.java @@ -66,7 +66,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -117,7 +117,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -150,7 +150,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -182,7 +182,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -225,7 +225,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -264,7 +264,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -301,7 +301,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -338,7 +338,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -374,7 +374,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -410,7 +410,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully removed"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -447,7 +447,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully removed"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -484,7 +484,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully added"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -528,7 +528,7 @@ public interface MgmtDistributionSetTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully added"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java index a9a1b2036..59cdbcd25 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java @@ -81,7 +81,7 @@ public final class MgmtRestConstants { */ public static final String ROLLOUT_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/rollouts"; /** - * The basic authentication validation mapping + * The basic auth validation mapping */ public static final String AUTH_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/userinfo"; /** diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java index ce2b0f539..6326241a3 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java @@ -65,7 +65,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -119,7 +119,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -152,7 +152,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -191,7 +191,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -234,7 +234,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "204", description = "Successfully approved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -268,7 +268,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "204", description = "Successfully denied"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -300,7 +300,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "204", description = "Successfully started"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -330,7 +330,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "204", description = "Successfully paused"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -361,7 +361,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "204", description = "Successfully stopped"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -394,7 +394,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -426,7 +426,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "204", description = "Successfully resumed"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -462,7 +462,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -520,7 +520,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -561,7 +561,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -616,7 +616,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "204", description = "Successfully triggered"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -646,7 +646,7 @@ public interface MgmtRolloutRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java index 2ccc8b35c..d2e3c3227 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java @@ -71,7 +71,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -113,7 +113,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -148,7 +148,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -183,7 +183,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -220,7 +220,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -270,7 +270,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -302,7 +302,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -336,7 +336,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -375,7 +375,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -405,7 +405,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -441,7 +441,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -473,7 +473,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -507,7 +507,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -539,7 +539,7 @@ public interface MgmtSoftwareModuleRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleTypeRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleTypeRestApi.java index 3405a5ae0..1f86bcb83 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleTypeRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleTypeRestApi.java @@ -65,7 +65,7 @@ public interface MgmtSoftwareModuleTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -116,7 +116,7 @@ public interface MgmtSoftwareModuleTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -149,7 +149,7 @@ public interface MgmtSoftwareModuleTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -182,7 +182,7 @@ public interface MgmtSoftwareModuleTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -225,7 +225,7 @@ public interface MgmtSoftwareModuleTypeRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetFilterQueryRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetFilterQueryRestApi.java index 14c449db4..7e73ef5f2 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetFilterQueryRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetFilterQueryRestApi.java @@ -59,7 +59,7 @@ public interface MgmtTargetFilterQueryRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -95,7 +95,7 @@ public interface MgmtTargetFilterQueryRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -147,7 +147,7 @@ public interface MgmtTargetFilterQueryRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -187,7 +187,7 @@ public interface MgmtTargetFilterQueryRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -227,7 +227,7 @@ public interface MgmtTargetFilterQueryRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -257,7 +257,7 @@ public interface MgmtTargetFilterQueryRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -289,7 +289,7 @@ public interface MgmtTargetFilterQueryRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -331,7 +331,7 @@ public interface MgmtTargetFilterQueryRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetGroupRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetGroupRestApi.java index eddb85889..09c89ee96 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetGroupRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetGroupRestApi.java @@ -9,6 +9,10 @@ */ package org.eclipse.hawkbit.mgmt.rest.api; +import static org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants.TARGET_GROUP_ORDER; + +import java.util.List; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.extensions.Extension; import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; @@ -31,10 +35,6 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; -import java.util.List; - -import static org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants.TARGET_GROUP_ORDER; - @Tag( name = "Target Groups", description = "REST API for Target Groups operations.", extensions = @Extension(name = OpenApi.X_HAWKBIT, properties = @ExtensionProperty(name = "order", value = TARGET_GROUP_ORDER))) @@ -60,7 +60,7 @@ public interface MgmtTargetGroupRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -113,7 +113,7 @@ public interface MgmtTargetGroupRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -163,7 +163,7 @@ public interface MgmtTargetGroupRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -199,7 +199,7 @@ public interface MgmtTargetGroupRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -235,7 +235,7 @@ public interface MgmtTargetGroupRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -268,7 +268,7 @@ public interface MgmtTargetGroupRestApi { @ApiResponse(responseCode = "204", description = "Successfully unassigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -295,7 +295,7 @@ public interface MgmtTargetGroupRestApi { @ApiResponse(responseCode = "204", description = "Successfully unassigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -320,7 +320,7 @@ public interface MgmtTargetGroupRestApi { description = "Handles the GET request of retrieving a list of all target groups.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -345,7 +345,7 @@ public interface MgmtTargetGroupRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetRestApi.java index 5464f4793..730a5786e 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetRestApi.java @@ -43,7 +43,6 @@ import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody; import org.eclipse.hawkbit.rest.OpenApi; import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; import org.springframework.hateoas.MediaTypes; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -53,7 +52,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; /** * API for handling target operations. @@ -76,7 +74,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -112,7 +110,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -163,7 +161,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -202,7 +200,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -242,7 +240,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -272,7 +270,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully unassigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -299,7 +297,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -326,7 +324,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -362,7 +360,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -418,7 +416,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted."), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -453,7 +451,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -487,7 +485,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -521,7 +519,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully updated"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -564,7 +562,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully updated confirmation status of the action"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies.", @@ -612,7 +610,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -647,7 +645,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -680,7 +678,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -726,7 +724,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -753,7 +751,7 @@ public interface MgmtTargetRestApi { @Operation(summary = "Return tags for specific target", description = "Get a paged list of tags for a target. Required permission: READ_REPOSITORY") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -783,7 +781,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -819,7 +817,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -850,7 +848,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -883,7 +881,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully updated"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or data volume restriction applies.", @@ -921,7 +919,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -950,7 +948,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or data volume restriction applies.", @@ -980,7 +978,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully activated auto-confirm"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -1017,7 +1015,7 @@ public interface MgmtTargetRestApi { @ApiResponse(responseCode = "204", description = "Successfully deactivated auto-confirm"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java index 5f25ad85d..0c56dc890 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java @@ -64,7 +64,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -109,7 +109,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "404", description = "Target tag not found.", @@ -136,7 +136,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -165,7 +165,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "200", description = "Successfully updated"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "404", description = "Target tag not found.", @@ -198,7 +198,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "404", description = "Target tag not found.", @@ -228,7 +228,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "404", description = "Target tag not found", @@ -277,7 +277,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @@ -308,7 +308,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully assigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "404", description = "Not Found - e.g. target tag not found. Contains info about not found.", @@ -344,7 +344,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully unassigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "404", description = "Target not found.", @@ -373,7 +373,7 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "204", description = "Successfully unassigned"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "401", description = "The request requires user auth."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), @ApiResponse(responseCode = "404", description = "Not Found - e.g. target tag not found. Contains info about not found.", diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTypeRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTypeRestApi.java index ac70c8529..4296741db 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTypeRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTypeRestApi.java @@ -65,7 +65,7 @@ public interface MgmtTargetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -116,7 +116,7 @@ public interface MgmtTargetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -148,7 +148,7 @@ public interface MgmtTargetTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -180,7 +180,7 @@ public interface MgmtTargetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully updated"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -222,7 +222,7 @@ public interface MgmtTargetTypeRestApi { @ApiResponse(responseCode = "201", description = "Successfully created"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -262,7 +262,7 @@ public interface MgmtTargetTypeRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -297,7 +297,7 @@ public interface MgmtTargetTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully removed"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -333,7 +333,7 @@ public interface MgmtTargetTypeRestApi { @ApiResponse(responseCode = "204", description = "Successfully added"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTenantManagementRestApi.java b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTenantManagementRestApi.java index 5c1bb1583..ac7b1210d 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTenantManagementRestApi.java +++ b/hawkbit-mgmt/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTenantManagementRestApi.java @@ -56,7 +56,7 @@ public interface MgmtTenantManagementRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -88,7 +88,7 @@ public interface MgmtTenantManagementRestApi { @ApiResponse(responseCode = "204", description = "Successfully deleted"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -120,7 +120,7 @@ public interface MgmtTenantManagementRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -156,7 +156,7 @@ public interface MgmtTenantManagementRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + @@ -198,7 +198,7 @@ public interface MgmtTenantManagementRestApi { @ApiResponse(responseCode = "200", description = "Successfully retrieved"), @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + @ApiResponse(responseCode = "401", description = "The request requires user auth.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtActionResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtActionResource.java index 09518db8f..c9e39718a 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtActionResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtActionResource.java @@ -11,6 +11,8 @@ package org.eclipse.hawkbit.mgmt.rest.resource; import static org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility.sanitizeActionSortParam; +import java.util.List; + import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.audit.AuditLog; import org.eclipse.hawkbit.mgmt.json.model.PagedList; @@ -29,8 +31,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - @Slf4j @RestController @ConditionalOnProperty(name = "hawkbit.rest.MgmtActionResource.enabled", matchIfMissing = true) diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtBasicAuthResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtBasicAuthResource.java index 1ba169c5c..dca1852a4 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtBasicAuthResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtBasicAuthResource.java @@ -10,9 +10,9 @@ package org.eclipse.hawkbit.mgmt.rest.resource; import org.eclipse.hawkbit.audit.AuditLog; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.mgmt.json.model.auth.MgmtUserInfo; import org.eclipse.hawkbit.mgmt.rest.api.MgmtBasicAuthRestApi; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -25,18 +25,12 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class MgmtBasicAuthResource implements MgmtBasicAuthRestApi { - private final TenantAware tenantAware; - - public MgmtBasicAuthResource(final TenantAware tenantAware) { - this.tenantAware = tenantAware; - } - @Override @AuditLog(entity = "BasicAuth", type = AuditLog.Type.READ, description = "Validate Basic Auth") public ResponseEntity validateBasicAuth() { final MgmtUserInfo userInfo = new MgmtUserInfo(); - userInfo.setTenant(tenantAware.getCurrentTenant()); - userInfo.setUsername(tenantAware.getCurrentUsername()); + userInfo.setTenant(AccessContext.tenant()); + userInfo.setUsername(AccessContext.actor()); final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null) { userInfo.setPermissions(authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).toArray(String[]::new)); diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java index 3d7745518..5402fe10a 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java @@ -55,8 +55,8 @@ import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.DeploymentRequest; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult; @@ -65,8 +65,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -89,7 +87,6 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { private final DeploymentManagement deployManagement; private final SystemManagement systemManagement; private final MgmtDistributionSetMapper mgmtDistributionSetMapper; - private final TenantConfigHelper tenantConfigHelper; @SuppressWarnings("java:S107") MgmtDistributionSetResource( @@ -99,9 +96,9 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { final DistributionSetInvalidationManagement distributionSetInvalidationManagement, final TargetManagement targetManagement, final TargetFilterQueryManagement targetFilterQueryManagement, - final DeploymentManagement deployManagement, final TenantConfigurationManagement tenantConfigurationManagement, + final DeploymentManagement deployManagement, final MgmtDistributionSetMapper mgmtDistributionSetMapper, - final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext) { + final SystemManagement systemManagement) { this.softwareModuleManagement = softwareModuleManagement; this.distributionSetManagement = distributionSetManagement; this.distributionSetTypeManagement = distributionSetTypeManagement; @@ -109,7 +106,6 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { this.targetManagement = targetManagement; this.targetFilterQueryManagement = targetFilterQueryManagement; this.deployManagement = deployManagement; - this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); this.mgmtDistributionSetMapper = mgmtDistributionSetMapper; this.systemManagement = systemManagement; } @@ -209,7 +205,7 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { } return ResponseEntity.ok(new PagedList<>( - MgmtTargetMapper.toResponse(targetsAssignedDS.getContent(), tenantConfigHelper), targetsAssignedDS.getTotalElements())); + MgmtTargetMapper.toResponse(targetsAssignedDS.getContent()), targetsAssignedDS.getTotalElements())); } @Override @@ -227,7 +223,7 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { } return ResponseEntity.ok(new PagedList<>( - MgmtTargetMapper.toResponse(targetsInstalledDS.getContent(), tenantConfigHelper), targetsInstalledDS.getTotalElements())); + MgmtTargetMapper.toResponse(targetsInstalledDS.getContent()), targetsInstalledDS.getTotalElements())); } @Override @@ -239,7 +235,8 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { .findByAutoAssignDSAndRsql(distributionSetId, rsqlParam, pageable); return ResponseEntity.ok(new PagedList<>( - MgmtTargetFilterQueryMapper.toResponse(targetFilterQueries.getContent(), tenantConfigHelper.isConfirmationFlowEnabled(), false), + MgmtTargetFilterQueryMapper.toResponse( + targetFilterQueries.getContent(), TenantConfigHelper.isUserConfirmationFlowEnabled(), false), targetFilterQueries.getTotalElements())); } @@ -256,13 +253,13 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { final List deploymentRequests = assignments.stream().map(dsAssignment -> { final boolean isConfirmationRequired = dsAssignment.getConfirmationRequired() == null - ? tenantConfigHelper.isConfirmationFlowEnabled() + ? TenantConfigHelper.isUserConfirmationFlowEnabled() : dsAssignment.getConfirmationRequired(); return MgmtDeploymentRequestMapper.createAssignmentRequestBuilder(dsAssignment, distributionSetId) .confirmationRequired(isConfirmationRequired).build(); }).toList(); - final List assignmentResults = deployManagement.assignDistributionSets(deploymentRequests); + final List assignmentResults = deployManagement.assignDistributionSets(deploymentRequests, null); return ResponseEntity.ok(mgmtDistributionSetMapper.toResponse(assignmentResults)); } diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtOpenApiConfiguration.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtOpenApiConfiguration.java index 9b1eda08a..17eff71f9 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtOpenApiConfiguration.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtOpenApiConfiguration.java @@ -80,7 +80,7 @@ public class MgmtOpenApiConfiguration { private static ServerVariable tenantSeverVariable() { final ServerVariable tenantServerVariable = new ServerVariable(); - tenantServerVariable.setDescription("Tenant identifier"); + tenantServerVariable.setDescription("AccessContext identifier"); tenantServerVariable.setDefault("DEFAULT"); return tenantServerVariable; } diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java index 46ebbf463..2c95e604a 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java @@ -37,9 +37,9 @@ import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.RolloutManagement.Create; import org.eclipse.hawkbit.repository.RolloutManagement.GroupCreate; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; @@ -47,8 +47,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -66,19 +64,15 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi { private final RolloutGroupManagement rolloutGroupManagement; private final DistributionSetManagement distributionSetManagement; private final TargetFilterQueryManagement targetFilterQueryManagement; - private final TenantConfigHelper tenantConfigHelper; MgmtRolloutResource( final RolloutManagement rolloutManagement, final RolloutGroupManagement rolloutGroupManagement, final DistributionSetManagement distributionSetManagement, - final TargetFilterQueryManagement targetFilterQueryManagement, - final SystemSecurityContext systemSecurityContext, - final TenantConfigurationManagement tenantConfigurationManagement) { + final TargetFilterQueryManagement targetFilterQueryManagement) { this.rolloutManagement = rolloutManagement; this.rolloutGroupManagement = rolloutGroupManagement; this.distributionSetManagement = distributionSetManagement; this.targetFilterQueryManagement = targetFilterQueryManagement; - this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); } @Override @@ -121,7 +115,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi { final DistributionSet distributionSet = distributionSetManagement.getValidAndComplete(rolloutRequestBody.getDistributionSetId()); final RolloutGroupConditions rolloutGroupConditions = MgmtRolloutMapper.fromRequest(rolloutRequestBody, true); final Create create = MgmtRolloutMapper.fromRequest(rolloutRequestBody, distributionSet); - final boolean confirmationFlowActive = tenantConfigHelper.isConfirmationFlowEnabled(); + final boolean confirmationFlowActive = TenantConfigHelper.isUserConfirmationFlowEnabled(); final Rollout rollout; if (rolloutRequestBody.getGroups() != null) { @@ -226,7 +220,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi { } final List rest = MgmtRolloutMapper.toResponseRolloutGroup( - rolloutGroups.getContent(), tenantConfigHelper.isConfirmationFlowEnabled(), isFullMode); + rolloutGroups.getContent(), TenantConfigHelper.isUserConfirmationFlowEnabled(), isFullMode); return ResponseEntity.ok(new PagedList<>(rest, rolloutGroups.getTotalElements())); } @@ -240,7 +234,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi { } return ResponseEntity.ok(MgmtRolloutMapper.toResponseRolloutGroup( - rolloutGroup, true, tenantConfigHelper.isConfirmationFlowEnabled())); + rolloutGroup, true, TenantConfigHelper.isUserConfirmationFlowEnabled())); } @Override @@ -255,7 +249,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi { } else { rolloutGroupTargets = this.rolloutGroupManagement.findTargetsOfRolloutGroupByRsql(groupId, rsqlParam, pageable); } - final List rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent(), tenantConfigHelper); + final List rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent()); return ResponseEntity.ok(new PagedList<>(rest, rolloutGroupTargets.getTotalElements())); } diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java index 760ef06d4..1c979a147 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java @@ -22,6 +22,8 @@ import java.util.Optional; import jakarta.validation.ValidationException; import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.artifact.model.ArtifactHashes; +import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver; import org.eclipse.hawkbit.audit.AuditLog; import org.eclipse.hawkbit.mgmt.json.model.PagedList; import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; @@ -38,8 +40,6 @@ import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement; import org.eclipse.hawkbit.repository.SystemManagement; -import org.eclipse.hawkbit.artifact.model.ArtifactHashes; -import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.ArtifactUpload; diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetFilterQueryResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetFilterQueryResource.java index d1b2e5b51..403360407 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetFilterQueryResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetFilterQueryResource.java @@ -27,12 +27,10 @@ import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetFilterQueryMapper import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.AutoAssignDistributionSetUpdate; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -47,14 +45,9 @@ import org.springframework.web.bind.annotation.RestController; public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestApi { private final TargetFilterQueryManagement filterManagement; - private final TenantConfigHelper tenantConfigHelper; - MgmtTargetFilterQueryResource( - final TargetFilterQueryManagement filterManagement, - final SystemSecurityContext systemSecurityContext, - final TenantConfigurationManagement tenantConfigurationManagement) { + MgmtTargetFilterQueryResource(final TargetFilterQueryManagement filterManagement) { this.filterManagement = filterManagement; - this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); } @Override @@ -62,7 +55,7 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA final TargetFilterQuery findTarget = findFilterWithExceptionIfNotFound(filterId); // to single response include poll status final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(findTarget, - tenantConfigHelper.isConfirmationFlowEnabled(), true); + TenantConfigHelper.isUserConfirmationFlowEnabled(), true); MgmtTargetFilterQueryMapper.addLinks(response); return ResponseEntity.ok(response); @@ -82,8 +75,8 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA final boolean isRepresentationFull = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL; - final List rest = MgmtTargetFilterQueryMapper - .toResponse(findTargetFiltersAll.getContent(), tenantConfigHelper.isConfirmationFlowEnabled(), isRepresentationFull); + final List rest = MgmtTargetFilterQueryMapper.toResponse( + findTargetFiltersAll.getContent(), TenantConfigHelper.isUserConfirmationFlowEnabled(), isRepresentationFull); return ResponseEntity.ok(new PagedList<>(rest, filterManagement.count())); } @@ -92,7 +85,7 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA final TargetFilterQuery createdTarget = filterManagement.create(MgmtTargetFilterQueryMapper.fromRequest(filter)); final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse( - createdTarget, tenantConfigHelper.isConfirmationFlowEnabled(), false); + createdTarget, TenantConfigHelper.isUserConfirmationFlowEnabled(), false); MgmtTargetFilterQueryMapper.addLinks(response); return new ResponseEntity<>(response, HttpStatus.CREATED); @@ -108,7 +101,7 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA .build()); final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter, - tenantConfigHelper.isConfirmationFlowEnabled(), false); + TenantConfigHelper.isUserConfirmationFlowEnabled(), false); MgmtTargetFilterQueryMapper.addLinks(response); return ResponseEntity.ok(response); @@ -141,7 +134,7 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA public ResponseEntity postAssignedDistributionSet( final Long filterId, final MgmtDistributionSetAutoAssignment autoAssignRequest) { final boolean confirmationRequired = autoAssignRequest.getConfirmationRequired() == null - ? tenantConfigHelper.isConfirmationFlowEnabled() + ? TenantConfigHelper.isUserConfirmationFlowEnabled() : autoAssignRequest.getConfirmationRequired(); final AutoAssignDistributionSetUpdate update = MgmtTargetFilterQueryMapper @@ -150,7 +143,7 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA final TargetFilterQuery updateFilter = filterManagement.updateAutoAssignDS(update); final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter, - tenantConfigHelper.isConfirmationFlowEnabled(), false); + TenantConfigHelper.isUserConfirmationFlowEnabled(), false); MgmtTargetFilterQueryMapper.addLinks(response); return ResponseEntity.ok(response); diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetGroupResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetGroupResource.java index 487079e73..e6d7c1029 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetGroupResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetGroupResource.java @@ -9,6 +9,10 @@ */ package org.eclipse.hawkbit.mgmt.rest.resource; +import static org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility.sanitizeTargetSortParam; + +import java.util.List; + import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.mgmt.json.model.PagedList; import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget; @@ -16,31 +20,21 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetGroupRestApi; import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetMapper; import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - -import static org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility.sanitizeTargetSortParam; - @Slf4j @RestController public class MgmtTargetGroupResource implements MgmtTargetGroupRestApi { private final TargetManagement targetManagement; - private final TenantConfigHelper tenantConfigHelper; public MgmtTargetGroupResource( - final TargetManagement targetManagement, - final TenantConfigurationManagement tenantConfigurationManagement, final SystemSecurityContext systemSecurityContext) { + final TargetManagement targetManagement) { this.targetManagement = targetManagement; - this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); } @Override @@ -50,7 +44,7 @@ public class MgmtTargetGroupResource implements MgmtTargetGroupRestApi { final Page targets = targetManagement.findTargetsByGroup(group, false, pageable); - final List rest = MgmtTargetMapper.toResponse(targets.getContent(), tenantConfigHelper); + final List rest = MgmtTargetMapper.toResponse(targets.getContent()); return ResponseEntity.ok(new PagedList<>(rest, targets.getTotalElements())); } @@ -61,7 +55,7 @@ public class MgmtTargetGroupResource implements MgmtTargetGroupRestApi { final Page targets = targetManagement.findTargetsByGroup(groupFilter, subgroups, pageable); - final List rest = MgmtTargetMapper.toResponse(targets.getContent(), tenantConfigHelper); + final List rest = MgmtTargetMapper.toResponse(targets.getContent()); return ResponseEntity.ok(new PagedList<>(rest, targets.getTotalElements())); } diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java index 6ba5c5761..da6131181 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java @@ -56,9 +56,9 @@ import org.eclipse.hawkbit.repository.ConfirmationManagement; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetTypeManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DeploymentRequest; @@ -66,8 +66,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetType; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -91,27 +89,24 @@ public class MgmtTargetResource implements MgmtTargetRestApi { private final DeploymentManagement deploymentManagement; private final MgmtTargetMapper mgmtTargetMapper; private final MgmtDistributionSetMapper mgmtDistributionSetMapper; - private final TenantConfigHelper tenantConfigHelper; MgmtTargetResource( final TargetManagement targetManagement, final TargetTypeManagement targetTypeManagement, final DeploymentManagement deploymentManagement, final ConfirmationManagement confirmationManagement, - final MgmtTargetMapper mgmtTargetMapper, final MgmtDistributionSetMapper mgmtDistributionSetMapper, - final SystemSecurityContext systemSecurityContext, final TenantConfigurationManagement tenantConfigurationManagement) { + final MgmtTargetMapper mgmtTargetMapper, final MgmtDistributionSetMapper mgmtDistributionSetMapper) { this.targetManagement = targetManagement; this.targetTypeManagement = targetTypeManagement; this.deploymentManagement = deploymentManagement; this.confirmationManagement = confirmationManagement; this.mgmtTargetMapper = mgmtTargetMapper; this.mgmtDistributionSetMapper = mgmtDistributionSetMapper; - this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); } @Override public ResponseEntity getTarget(final String targetId) { final Target findTarget = targetManagement.getByControllerId(targetId); // to single response include poll status - final MgmtTarget response = MgmtTargetMapper.toResponse(findTarget, tenantConfigHelper, null); + final MgmtTarget response = MgmtTargetMapper.toResponse(findTarget, null); MgmtTargetMapper.addTargetLinks(response); return ResponseEntity.ok(response); @@ -128,7 +123,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi { findTargetsAll = targetManagement.findAll(pageable); } - final List rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper); + final List rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent()); return ResponseEntity.ok(new PagedList<>(rest, findTargetsAll.getTotalElements())); } @@ -137,7 +132,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi { log.debug("creating {} targets", targets.size()); final Collection createdTargets = this.targetManagement.create(mgmtTargetMapper.fromRequest(targets)); log.debug("{} targets created, return status {}", targets.size(), HttpStatus.CREATED); - return new ResponseEntity<>(MgmtTargetMapper.toResponse(createdTargets, tenantConfigHelper), HttpStatus.CREATED); + return new ResponseEntity<>(MgmtTargetMapper.toResponse(createdTargets), HttpStatus.CREATED); } @Override @@ -166,7 +161,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi { .requestControllerAttributes(targetRest.getRequestAttributes()) .build()); - final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget, tenantConfigHelper, null); + final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget, null); MgmtTargetMapper.addTargetLinks(response); return ResponseEntity.ok(response); @@ -399,14 +394,13 @@ public class MgmtTargetResource implements MgmtTargetRestApi { final List deploymentRequests = dsAssignments.stream().map(dsAssignment -> { final boolean isConfirmationRequired = dsAssignment.getConfirmationRequired() == null - ? tenantConfigHelper.isConfirmationFlowEnabled() + ? TenantConfigHelper.isUserConfirmationFlowEnabled() : dsAssignment.getConfirmationRequired(); return MgmtDeploymentRequestMapper.createAssignmentRequestBuilder(dsAssignment, targetId) .confirmationRequired(isConfirmationRequired).build(); }).toList(); - final List assignmentResults = deploymentManagement - .assignDistributionSets(deploymentRequests); + final List assignmentResults = deploymentManagement.assignDistributionSets(deploymentRequests, null); return ResponseEntity.ok(mgmtDistributionSetMapper.toResponse(assignmentResults)); } @@ -486,6 +480,6 @@ public class MgmtTargetResource implements MgmtTargetRestApi { } private R getNullIfEmpty(final T object, final Function extractMethod) { - return object == null ? null : extractMethod.apply(object); + return ObjectUtils.isEmpty(object) ? null : extractMethod.apply(object); } } \ No newline at end of file diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResource.java index a200d76a9..6fbee6b97 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResource.java @@ -27,12 +27,9 @@ import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetMapper; import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetTagManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -48,14 +45,11 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi { private final TargetTagManagement tagManagement; private final TargetManagement targetManagement; - private final TenantConfigHelper tenantConfigHelper; MgmtTargetTagResource( - final TargetTagManagement tagManagement, final TargetManagement targetManagement, - final SystemSecurityContext securityContext, final TenantConfigurationManagement configurationManagement) { + final TargetTagManagement tagManagement, final TargetManagement targetManagement) { this.tagManagement = tagManagement; this.targetManagement = targetManagement; - tenantConfigHelper = TenantConfigHelper.usingContext(securityContext, configurationManagement); } @Override @@ -129,7 +123,7 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi { findTargetsAll = targetManagement.findByRsqlAndTag(rsqlParam, targetTagId, pageable); } - final List rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper); + final List rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent()); return ResponseEntity.ok(new PagedList<>(rest, findTargetsAll.getTotalElements())); } diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTypeResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTypeResource.java index 76202da3a..9d35c93cf 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTypeResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTypeResource.java @@ -33,7 +33,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.RestController; /** diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTenantManagementResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTenantManagementResource.java index 31f078d80..76ce38cc0 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTenantManagementResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTenantManagementResource.java @@ -22,9 +22,9 @@ import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationV import org.eclipse.hawkbit.mgmt.rest.api.MgmtTenantManagementRestApi; import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTenantManagementMapper; import org.eclipse.hawkbit.repository.SystemManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.exception.TenantConfigurationValidatorException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.springframework.http.HttpStatus; @@ -38,22 +38,19 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi { - private final TenantConfigurationManagement tenantConfigurationManagement; private final TenantConfigurationProperties tenantConfigurationProperties; private final SystemManagement systemManagement; MgmtTenantManagementResource( - final TenantConfigurationManagement tenantConfigurationManagement, final TenantConfigurationProperties tenantConfigurationProperties, final SystemManagement systemManagement) { - this.tenantConfigurationManagement = tenantConfigurationManagement; this.tenantConfigurationProperties = tenantConfigurationProperties; this.systemManagement = systemManagement; } @Override public ResponseEntity> getTenantConfiguration() { - // Load and Construct default Tenant Configuration + // Load and Construct default AccessContext Configuration final Map tenantConfigurationValueMap = new HashMap<>(); tenantConfigurationProperties.getConfigurationKeys().forEach(key -> { try { @@ -74,14 +71,14 @@ public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi } @Override - @AuditLog(entity = "TenantConfiguration", type = AuditLog.Type.DELETE, description = "Delete Tenant Configuration Value") + @AuditLog(entity = "TenantConfiguration", type = AuditLog.Type.DELETE, description = "Delete AccessContext Configuration Value") public ResponseEntity deleteTenantConfigurationValue(final String keyName) { - //Default DistributionSet Type cannot be deleted as is part of TenantMetadata + // Default DistributionSet Type cannot be deleted as is part of TenantMetadata if (isDefaultDistributionSetTypeKey(keyName)) { return ResponseEntity.badRequest().build(); } - tenantConfigurationManagement.deleteConfiguration(keyName); + TenantConfigHelper.getTenantConfigurationManagement().deleteConfiguration(keyName); log.debug("{} config value deleted, return status {}", keyName, HttpStatus.OK); return ResponseEntity.noContent().build(); @@ -93,7 +90,7 @@ public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi } @Override - @AuditLog(entity = "TenantConfiguration", type = AuditLog.Type.UPDATE, description = "Update Tenant Configuration Value") + @AuditLog(entity = "TenantConfiguration", type = AuditLog.Type.UPDATE, description = "Update AccessContext Configuration Value") public ResponseEntity updateTenantConfigurationValue( final String keyName, final MgmtSystemTenantConfigurationValueRequest configurationValueRest) { Serializable configurationValue = configurationValueRest.getValue(); @@ -101,7 +98,8 @@ public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi if (isDefaultDistributionSetTypeKey(keyName)) { responseUpdatedValue = updateDefaultDsType(configurationValue); } else { - final TenantConfigurationValue updatedTenantConfigurationValue = tenantConfigurationManagement + final TenantConfigurationValue updatedTenantConfigurationValue = TenantConfigHelper + .getTenantConfigurationManagement() .addOrUpdateConfiguration(keyName, configurationValueRest.getValue()); responseUpdatedValue = MgmtTenantManagementMapper.toResponseTenantConfigurationValue(keyName, updatedTenantConfigurationValue); } @@ -110,7 +108,7 @@ public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi } @Override - @AuditLog(entity = "TenantConfiguration", type = AuditLog.Type.UPDATE, description = "Update Tenant Configuration") + @AuditLog(entity = "TenantConfiguration", type = AuditLog.Type.UPDATE, description = "Update AccessContext Configuration") public ResponseEntity> updateTenantConfiguration( final Map configurationValueMap) { final boolean containsNull = configurationValueMap.keySet().stream().anyMatch(Objects::isNull); @@ -130,7 +128,7 @@ public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi //try update TenantConfiguration, in case of Error -> rollback TenantMetadata final Map> tenantConfigurationValues; try { - tenantConfigurationValues = tenantConfigurationManagement.addOrUpdateConfiguration(configurationValueMap); + tenantConfigurationValues = TenantConfigHelper.getTenantConfigurationManagement().addOrUpdateConfiguration(configurationValueMap); } catch (Exception ex) { //if DefaultDsType was updated, rollback it in case of TenantConfiguration update. if (updatedDefaultDsType != null) { @@ -155,13 +153,13 @@ public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi } private MgmtSystemTenantConfigurationValue loadTenantConfigurationValueBy(final String keyName) { - //Check if requested key is TenantConfiguration or TenantMetadata, load it and return it as rest response + // Check if requested key is TenantConfiguration or TenantMetadata, load it and return it as rest response final MgmtSystemTenantConfigurationValue response; if (isDefaultDistributionSetTypeKey(keyName)) { response = MgmtTenantManagementMapper.toResponseDefaultDsType(systemManagement.getTenantMetadata().getDefaultDsType().getId()); } else { response = MgmtTenantManagementMapper.toResponseTenantConfigurationValue( - keyName, tenantConfigurationManagement.getConfigurationValue(keyName)); + keyName, TenantConfigHelper.getTenantConfigurationManagement().getConfigurationValue(keyName)); } return response; } diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/mapper/MgmtSoftwareModuleMapper.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/mapper/MgmtSoftwareModuleMapper.java index e96b003f0..39caa9947 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/mapper/MgmtSoftwareModuleMapper.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/mapper/MgmtSoftwareModuleMapper.java @@ -33,7 +33,6 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi; import org.eclipse.hawkbit.mgmt.rest.resource.MgmtDownloadArtifactResource; import org.eclipse.hawkbit.mgmt.rest.resource.MgmtSoftwareModuleResource; -import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SoftwareModuleManagement.Create; import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement; import org.eclipse.hawkbit.repository.SystemManagement; diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/mapper/MgmtTargetMapper.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/mapper/MgmtTargetMapper.java index 9ce025de3..522bb2ca8 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/mapper/MgmtTargetMapper.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/mapper/MgmtTargetMapper.java @@ -39,12 +39,11 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi; import org.eclipse.hawkbit.mgmt.rest.api.SortDirection; -import org.eclipse.hawkbit.repository.qfields.ActionFields; -import org.eclipse.hawkbit.repository.qfields.ActionStatusFields; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.TargetManagement.Create; import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.ActionStatus; @@ -54,9 +53,10 @@ import org.eclipse.hawkbit.repository.model.PollStatus; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetType; +import org.eclipse.hawkbit.repository.qfields.ActionFields; +import org.eclipse.hawkbit.repository.qfields.ActionStatusFields; import org.eclipse.hawkbit.rest.json.model.ResponseList; -import org.eclipse.hawkbit.util.IpUtil; -import org.eclipse.hawkbit.utils.TenantConfigHelper; +import org.eclipse.hawkbit.utils.IpUtil; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; @@ -119,30 +119,16 @@ public final class MgmtTargetMapper { return response; } - /** - * Create a response for targets. - * - * @param targets list of targets - * @return the response - */ - public static List toResponse(final Collection targets, final TenantConfigHelper configHelper) { + public static List toResponse(final Collection targets) { if (targets == null) { return Collections.emptyList(); } - final Function pollStatusResolver = configHelper.pollStatusResolver(); - return new ResponseList<>( - targets.stream().map(target -> toResponse(target, configHelper, pollStatusResolver)).toList()); + final Function pollStatusResolver = TenantConfigHelper.pollStatusResolver(); + return new ResponseList<>(targets.stream().map(target -> toResponse(target, pollStatusResolver)).toList()); } - /** - * Create a response for target. - * - * @param target the target - * @return the response - */ - public static MgmtTarget toResponse( - final Target target, final TenantConfigHelper configHelper, final Function pollStatusResolver) { + public static MgmtTarget toResponse(final Target target, final Function pollStatusResolver) { if (target == null) { return null; } @@ -189,13 +175,14 @@ public final class MgmtTargetMapper { targetRest.setTargetType(target.getTargetType().getId()); targetRest.setTargetTypeName(target.getTargetType().getName()); } - if (configHelper.isConfirmationFlowEnabled()) { + + if (TenantConfigHelper.isUserConfirmationFlowEnabled()) { targetRest.setAutoConfirmActive(target.getAutoConfirmationStatus() != null); } targetRest.add(linkTo(methodOn(MgmtTargetRestApi.class).getTarget(target.getControllerId())).withSelfRel().expand()); - addPollStatus(target, targetRest, pollStatusResolver == null ? configHelper.pollStatusResolver() : pollStatusResolver); + addPollStatus(target, targetRest, pollStatusResolver == null ? TenantConfigHelper.pollStatusResolver() : pollStatusResolver); return targetRest; } diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/util/PagingUtility.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/util/PagingUtility.java index a145cd4ce..ee8c7be0b 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/util/PagingUtility.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/util/PagingUtility.java @@ -12,11 +12,11 @@ package org.eclipse.hawkbit.mgmt.rest.resource.util; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.qfields.ActionFields; import org.eclipse.hawkbit.repository.qfields.ActionStatusFields; import org.eclipse.hawkbit.repository.qfields.DistributionSetFields; import org.eclipse.hawkbit.repository.qfields.DistributionSetTypeFields; -import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.qfields.RolloutFields; import org.eclipse.hawkbit.repository.qfields.RolloutGroupFields; import org.eclipse.hawkbit.repository.qfields.SoftwareModuleFields; diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtBasicAuthResourceTest.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtBasicAuthResourceTest.java index 35d627dc3..a97dddeca 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtBasicAuthResourceTest.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtBasicAuthResourceTest.java @@ -24,8 +24,8 @@ import org.eclipse.hawkbit.repository.jpa.JpaRepositoryConfiguration; import org.eclipse.hawkbit.repository.test.TestConfiguration; import org.eclipse.hawkbit.repository.test.matcher.EventVerifier; import org.eclipse.hawkbit.repository.test.util.CleanupTestExecutionListener; -import org.eclipse.hawkbit.repository.test.util.TestLoggerExtension; import org.eclipse.hawkbit.repository.test.util.SharedSqlTestDatabaseExtension; +import org.eclipse.hawkbit.repository.test.util.TestLoggerExtension; import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.RestConfiguration; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java index 48ef96a65..098fc2d1b 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java @@ -1954,13 +1954,13 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { private void awaitRunningState(final Long rolloutId) { awaitRollout().until(() -> SecurityContextSwitch - .callAsPrivileged(() -> rolloutManagement.get(rolloutId)) + .asPrivileged(() -> rolloutManagement.get(rolloutId)) .getStatus().equals(RolloutStatus.RUNNING)); } private void awaitActionStatus(final Long actionId, final Status status) { awaitRollout().until(() -> SecurityContextSwitch - .callAsPrivileged(() -> deploymentManagement.findAction(actionId).orElseThrow(NoSuchElementException::new)) + .asPrivileged(() -> deploymentManagement.findAction(actionId).orElseThrow(NoSuchElementException::new)) .getStatus().equals(status)); } diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetGroupResourceTest.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetGroupResourceTest.java index 132891c9a..549ebda21 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetGroupResourceTest.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetGroupResourceTest.java @@ -9,22 +9,22 @@ */ package org.eclipse.hawkbit.mgmt.rest.resource; -import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static org.eclipse.hawkbit.repository.TargetManagement.Create.*; +import static org.eclipse.hawkbit.repository.TargetManagement.Create.builder; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; + public class MgmtTargetGroupResourceTest extends AbstractManagementApiIntegrationTest { diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java index 791fa180d..81c31e75b 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java @@ -47,14 +47,13 @@ import jakarta.validation.ConstraintViolationException; import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.exception.SpServerError; -import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionConfirmationRequestBodyPut; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType; import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAutoConfirmUpdate; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility; -import org.eclipse.hawkbit.repository.qfields.ActionFields; import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.repository.TargetManagement.Create; import org.eclipse.hawkbit.repository.TargetTypeManagement; @@ -75,11 +74,12 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.qfields.ActionFields; import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.exception.MessageNotReadableException; import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.utils.IpUtil; import org.hamcrest.Matchers; import org.json.JSONArray; import org.json.JSONObject; diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTypeResourceTest.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTypeResourceTest.java index 3078a8866..543912063 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTypeResourceTest.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTypeResourceTest.java @@ -30,8 +30,8 @@ import java.util.List; import java.util.Set; import com.jayway.jsonpath.JsonPath; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.exception.SpServerError; -import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.mgmt.json.model.MgmtId; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.TargetManagement; diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTenantManagementResourceTest.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTenantManagementResourceTest.java index 2399473c9..9aa5e6640 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTenantManagementResourceTest.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTenantManagementResourceTest.java @@ -12,6 +12,11 @@ package org.eclipse.hawkbit.mgmt.rest.resource; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.callAs; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.getAs; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.withUser; +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 static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED; +import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED; +import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; @@ -21,13 +26,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValueRequest; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.DistributionSetTypeManagement; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.json.JSONObject; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; @@ -37,18 +41,10 @@ import org.springframework.test.web.servlet.ResultMatcher; * Spring MVC Tests against the MgmtTenantManagementResource. *

* Feature: Component Tests - Management API
- * Story: Tenant Management Resource + * Story: AccessContext Management Resource */ public class MgmtTenantManagementResourceTest extends AbstractManagementApiIntegrationTest { - private static final String KEY_MULTI_ASSIGNMENTS = "multi.assignments.enabled"; - - private static final String KEY_AUTO_CLOSE = "repository.actions.autoclose.enabled"; - private static final String ROLLOUT_APPROVAL_ENABLED = "rollout.approval.enabled"; - - private static final String AUTHENTICATION_GATEWAYTOKEN_ENABLED = "authentication.gatewaytoken.enabled"; - - private static final String AUTHENTICATION_GATEWAYTOKEN_KEY = "authentication.gatewaytoken.key"; private static final String DEFAULT_DISTRIBUTION_SET_TYPE_KEY = "default.ds.type"; /** @@ -71,8 +67,7 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg @Test void getTenantConfiguration() throws Exception { //Test TenantConfiguration property - mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", - TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY)) + mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); } @@ -101,7 +96,7 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg final String json = mapper.writeValueAsString(bodyPut); mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", - TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY).content(json) + AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY).content(json) .contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); @@ -156,12 +151,12 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg final String bodyActivate = new JSONObject().put("value", true).toString(); final String bodyDeactivate = new JSONObject().put("value", false).toString(); - mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS) + mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", MULTI_ASSIGNMENTS_ENABLED) .content(bodyActivate).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); - mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS) + mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", MULTI_ASSIGNMENTS_ENABLED) .content(bodyDeactivate).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isForbidden()); @@ -177,8 +172,8 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg // TenantMetadata - DefaultDSType ID is valid, //in the end batch configuration update must fail, and thus, not a single config should be actually changed long testValidDistributionSetType = createTestDistributionSetType(); - boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(); - String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(); + boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement().getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(); + String oldAuthGatewayToken = (String) tenantConfigurationManagement().getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY).getValue(); //test TenantConfiguration with invalid config value, and a valid TenantMetadata - Default DistributionSetType id assertBatchConfigurationFails(!oldRolloutApprovalConfig, "invalid-config-value", oldAuthGatewayToken + "randomSuffix0", testValidDistributionSetType, status().isBadRequest()); @@ -193,10 +188,10 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg // all TenantConfiguration have valid and new values - using old values, inverted // TenantMetadata - DefaultDSType ID is invalid //in the end batch configuration update must fail, and thus, not a single config should be actually changed. - boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(); - boolean oldAuthGatewayTokenEnabled = (Boolean) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED) - .getValue(); - String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(); + boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement().getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(); + boolean oldAuthGatewayTokenEnabled = (Boolean) tenantConfigurationManagement() + .getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED).getValue(); + String oldAuthGatewayToken = (String) tenantConfigurationManagement().getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY).getValue(); //invalid TenantMetadata Default DistributionSetType, it is expected to be a number. Testing invalid type - string //not a single configuration should be changed after the failure @@ -228,27 +223,26 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg String updatedAuthGatewayTokenKey = "54321"; JSONObject configuration = new JSONObject(); configuration.put(ROLLOUT_APPROVAL_ENABLED, updatedRolloutApprovalEnabled); - configuration.put(AUTHENTICATION_GATEWAYTOKEN_ENABLED, updatedAuthGatewayTokenEnabled); - configuration.put(AUTHENTICATION_GATEWAYTOKEN_KEY, updatedAuthGatewayTokenKey); + configuration.put(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED, updatedAuthGatewayTokenEnabled); + configuration.put(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, updatedAuthGatewayTokenKey); configuration.put(DEFAULT_DISTRIBUTION_SET_TYPE_KEY, updatedDistributionSetType); String body = configuration.toString(); - mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs") - .content(body).contentType(MediaType.APPLICATION_JSON)) + mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs") .content(body).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); //assert all changes were applied after Rest Success assertEquals(updatedDistributionSetType, getActualDefaultDsType(), "Change BatchConfiguration was successful but TenantMetadata - Default DistributionSetType was not actually changed."); - assertEquals(updatedRolloutApprovalEnabled, tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(), + assertEquals(updatedRolloutApprovalEnabled, tenantConfigurationManagement().getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(), "Change BatchConfiguration was successful but TenantConfiguration property was not actually changed."); assertEquals(updatedAuthGatewayTokenEnabled, - tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED).getValue(), + tenantConfigurationManagement().getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED).getValue(), "Change BatchConfiguration was successful but TenantConfiguration property was not actually changed."); assertEquals(updatedAuthGatewayTokenKey, - tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(), + tenantConfigurationManagement().getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY).getValue(), "Change BatchConfiguration was successful but TenantConfiguration property was not actually changed."); } @@ -261,19 +255,19 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg final String bodyDeactivate = new JSONObject().put("value", false).toString(); // enable Multi-Assignments - mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS) + mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", MULTI_ASSIGNMENTS_ENABLED) .content(bodyActivate).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // try to enable Auto-Close - mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_AUTO_CLOSE) + mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED) .content(bodyActivate).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isForbidden()); // try to disable Auto-Close - mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_AUTO_CLOSE) + mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED) .content(bodyDeactivate).contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isForbidden()); @@ -285,7 +279,7 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg @Test void deleteTenantConfiguration() throws Exception { mvc.perform(delete(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", - TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY)) + AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isNoContent()); } @@ -307,8 +301,8 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg @Test void getTenantConfigurationReadGWToken() throws Exception { getAs(withUser("tenant_admin", SpPermission.TENANT_CONFIGURATION), () -> { - tenantConfigurationManagement.addOrUpdateConfiguration( - TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, "123"); + tenantConfigurationManagement().addOrUpdateConfiguration( + AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, "123"); return null; }); @@ -319,8 +313,8 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg .andDo(MockMvcResultPrinter.print()) .andDo(m -> System.out.println("-> 1: " + m.getResponse().getContentAsString())) .andExpect(status().isOk()) - .andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "']").exists()) - .andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "'].value", equalTo("123"))); + .andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY + "']").exists()) + .andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY + "'].value", equalTo("123"))); return null; }); @@ -329,7 +323,7 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg .andDo(MockMvcResultPrinter.print()) .andDo(m -> System.out.println("-> 2: " + m.getResponse().getContentAsString())) .andExpect(status().isOk()) - .andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "']").doesNotExist()); + .andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY + "']").doesNotExist()); return null; }); } @@ -356,15 +350,15 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg private void assertBatchConfigurationFails(Object newRolloutApprovalEnabled, Object newAuthGatewayTokenEnabled, Object newGatewayToken, Object newDistributionSetTypeId, ResultMatcher resultMatchers) throws Exception { long oldDefaultDsType = getActualDefaultDsType(); - boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(); - boolean oldAuthGatewayTokenEnabled = (Boolean) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED) + boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement().getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(); + boolean oldAuthGatewayTokenEnabled = (Boolean) tenantConfigurationManagement().getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED) .getValue(); - String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(); + String oldAuthGatewayToken = (String) tenantConfigurationManagement().getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY).getValue(); JSONObject configuration = new JSONObject(); configuration.put(ROLLOUT_APPROVAL_ENABLED, newRolloutApprovalEnabled); - configuration.put(AUTHENTICATION_GATEWAYTOKEN_ENABLED, newAuthGatewayTokenEnabled); - configuration.put(AUTHENTICATION_GATEWAYTOKEN_KEY, newGatewayToken); + configuration.put(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED, newAuthGatewayTokenEnabled); + configuration.put(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, newGatewayToken); configuration.put(DEFAULT_DISTRIBUTION_SET_TYPE_KEY, newDistributionSetTypeId); String body = configuration.toString(); @@ -375,12 +369,12 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg //Check if TenantMetadata and TenantConfiguration is not changed as Batch config failed assertEquals(oldDefaultDsType, getActualDefaultDsType(), "Batch configuration update Failed, but TenantMetadata - DistributionSetType was actually changed."); - assertEquals(oldRolloutApprovalConfig, tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(), + assertEquals(oldRolloutApprovalConfig, tenantConfigurationManagement().getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(), "Batch configuration update Failed, but TenantConfiguration was actually changed."); assertEquals(oldAuthGatewayTokenEnabled, - tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED).getValue(), + tenantConfigurationManagement().getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED).getValue(), "Batch configuration update Failed, but TenantConfiguration was actually changed."); - assertEquals(oldAuthGatewayToken, tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(), + assertEquals(oldAuthGatewayToken, tenantConfigurationManagement().getConfigurationValue(AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY).getValue(), "Batch configuration update Failed, but TenantConfiguration was actually changed."); } diff --git a/hawkbit-mgmt/hawkbit-mgmt-server/src/test/java/org/eclipse/hawkbit/app/mgmt/CorsTest.java b/hawkbit-mgmt/hawkbit-mgmt-server/src/test/java/org/eclipse/hawkbit/app/mgmt/CorsTest.java index 27e0a9f42..f4008fac4 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-server/src/test/java/org/eclipse/hawkbit/app/mgmt/CorsTest.java +++ b/hawkbit-mgmt/hawkbit-mgmt-server/src/test/java/org/eclipse/hawkbit/app/mgmt/CorsTest.java @@ -14,7 +14,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.jupiter.api.Test; diff --git a/hawkbit-mgmt/hawkbit-mgmt-server/src/test/java/org/eclipse/hawkbit/app/mgmt/PreAuthorizeEnabledTest.java b/hawkbit-mgmt/hawkbit-mgmt-server/src/test/java/org/eclipse/hawkbit/app/mgmt/PreAuthorizeEnabledTest.java index 064350c45..cdc87062c 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-server/src/test/java/org/eclipse/hawkbit/app/mgmt/PreAuthorizeEnabledTest.java +++ b/hawkbit-mgmt/hawkbit-mgmt-server/src/test/java/org/eclipse/hawkbit/app/mgmt/PreAuthorizeEnabledTest.java @@ -16,8 +16,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import java.util.HashMap; import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; @@ -87,7 +87,7 @@ class PreAuthorizeEnabledTest extends AbstractSecurityTest { } /** - * Tests whether read tenant config request fail if a tenant config (or read read) is not granted for the user + * Tests whether read tenant config request fail if a tenant config (or read) is not granted for the user */ @Test @WithUser(authorities = { SpPermission.READ_TARGET }, autoCreateTenant = false) diff --git a/hawkbit-mgmt/hawkbit-mgmt-starter/pom.xml b/hawkbit-mgmt/hawkbit-mgmt-starter/pom.xml index 98ffca23e..690cd867c 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-starter/pom.xml +++ b/hawkbit-mgmt/hawkbit-mgmt-starter/pom.xml @@ -23,11 +23,6 @@ - - org.eclipse.hawkbit - hawkbit-security-core - ${project.version} - org.eclipse.hawkbit hawkbit-artifact-fs diff --git a/hawkbit-mgmt/hawkbit-mgmt-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/MgmtSecurityConfiguration.java b/hawkbit-mgmt/hawkbit-mgmt-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/MgmtSecurityConfiguration.java index ffc319a9a..d6cb03825 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/MgmtSecurityConfiguration.java +++ b/hawkbit-mgmt/hawkbit-mgmt-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/MgmtSecurityConfiguration.java @@ -9,17 +9,20 @@ */ package org.eclipse.hawkbit.autoconfigure.mgmt; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; + import java.io.Serial; +import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Collection; import java.util.Map; import java.util.Optional; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.context.Mdc; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.oidc.OidcProperties; import org.eclipse.hawkbit.oidc.OidcProperties.Oauth2.ResourceServer.Jwt.Claim; @@ -27,8 +30,6 @@ import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.rest.SecurityManagedConfiguration; import org.eclipse.hawkbit.rest.security.DosFilter; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.security.MdcHandler; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.tenancy.TenantAwareUser; import org.springframework.beans.factory.annotation.Autowired; @@ -105,11 +106,10 @@ public class MgmtSecurityConfiguration { final HttpSecurity http, @Autowired(required = false) @Qualifier("hawkbitOAuth2ResourceServerCustomizer") final Customizer> oauth2ResourceServerCustomizer, // called just before build of the SecurityFilterChain. - // could be used for instance to set authentication provider + // could be used for instance to set auth provider // Note: implementation of the customizer shall always take in account what is the already set by the hawkBit @Autowired(required = false) @Qualifier("hawkbitHttpSecurityCustomizer") final Customizer httpSecurityCustomizer, - final SystemManagement systemManagement, - final SystemSecurityContext systemSecurityContext) throws Exception { + final SystemManagement systemManagement) throws Exception { http .securityMatcher(MgmtRestConstants.BASE_REST_MAPPING + "/**", MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**") .authorizeHttpRequests(amrmRegistry -> amrmRegistry @@ -120,11 +120,11 @@ public class MgmtSecurityConfiguration { .anonymous(AbstractHttpConfigurer::disable) .csrf(AbstractHttpConfigurer::disable) .addFilterAfter( - // Servlet filter to create metadata after successful authentication over RESTful. + // Servlet filter to create metadata after successful auth over RESTful. (request, response, chain) -> { final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.isAuthenticated()) { - systemSecurityContext.runAsSystem(systemManagement::getTenantMetadataWithoutDetails); + asSystem(systemManagement::getTenantMetadataWithoutDetails); } chain.doFilter(request, response); }, @@ -156,7 +156,7 @@ public class MgmtSecurityConfiguration { httpSecurityCustomizer.customize(http); } - MdcHandler.Filter.addMdcFilter(http); + Mdc.Filter.addMdcFilter(http); return http.build(); } diff --git a/hawkbit-monolith/hawkbit-update-server/src/main/resources/application.properties b/hawkbit-monolith/hawkbit-update-server/src/main/resources/application.properties index b53cfc9d7..b47a4f05d 100644 --- a/hawkbit-monolith/hawkbit-update-server/src/main/resources/application.properties +++ b/hawkbit-monolith/hawkbit-update-server/src/main/resources/application.properties @@ -32,7 +32,7 @@ server.servlet.encoding.charset=UTF-8 server.servlet.encoding.enabled=true server.servlet.encoding.force=true -# DDI authentication configuration +# DDI auth configuration hawkbit.server.ddi.security.authentication.targettoken.enabled=false hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false diff --git a/hawkbit-monolith/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/CorsTest.java b/hawkbit-monolith/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/CorsTest.java index c64da218f..4259aec3e 100644 --- a/hawkbit-monolith/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/CorsTest.java +++ b/hawkbit-monolith/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/CorsTest.java @@ -14,7 +14,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.jupiter.api.Test; diff --git a/hawkbit-monolith/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/PreAuthorizeEnabledTest.java b/hawkbit-monolith/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/PreAuthorizeEnabledTest.java index 040a51fdc..f797393ad 100644 --- a/hawkbit-monolith/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/PreAuthorizeEnabledTest.java +++ b/hawkbit-monolith/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/PreAuthorizeEnabledTest.java @@ -16,8 +16,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import java.util.HashMap; import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; diff --git a/hawkbit-repository/hawkbit-repository-api/pom.xml b/hawkbit-repository/hawkbit-repository-api/pom.xml index 0e3b67592..b09875707 100644 --- a/hawkbit-repository/hawkbit-repository-api/pom.xml +++ b/hawkbit-repository/hawkbit-repository-api/pom.xml @@ -34,7 +34,7 @@ org.eclipse.hawkbit - hawkbit-security-core + hawkbit-core ${project.version} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java index cd14c6e05..89284d214 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ConfirmationManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ConfirmationManagement.java index 4e2eb0de0..cde5c09af 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ConfirmationManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ConfirmationManagement.java @@ -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} */ diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java index 2c54bf284..cf25cc349 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java index 1152042ce..d7e256bc2 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java @@ -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 assignDistributionSets(@Valid @NotEmpty List 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 assignDistributionSets( - String initiatedBy, @Valid @NotEmpty List deploymentRequests, String actionMessage); + @Valid @NotEmpty List 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 offlineAssignedDistributionSets(String initiatedBy, Collection> assignments); - @PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET) List offlineAssignedDistributionSets(Collection> assignments); diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetInvalidationManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetInvalidationManagement.java index ab08a1b9d..29a10788b 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetInvalidationManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetInvalidationManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index 9455620ff..9ce53a1b4 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagManagement.java index b97954da8..6cf17dc02 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTagManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeManagement.java index c45de6d7a..634f400f7 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetTypeManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/MetadataSupport.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/MetadataSupport.java index 4145a9754..86f4fafcf 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/MetadataSupport.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/MetadataSupport.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryManagement.java index 0b2156ea3..818340d68 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RepositoryManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutExecutor.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutExecutor.java index f5b1b8dd1..3ea9e5c83 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutExecutor.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutExecutor.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java index f6a571c16..9b476e09b 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutHandler.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutHandler.java index 10b4a8453..aa27640a2 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutHandler.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutHandler.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java index d0db902fd..0a68afdc7 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java @@ -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; diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SecurityTokenGenerator.java similarity index 56% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java rename to hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SecurityTokenGenerator.java index 1bb0e23a9..4847c2b37 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SecurityTokenGenerator.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others + * 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 @@ -7,29 +7,31 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hawkbit.security; +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 security token generator service which can be used to generate security - * tokens for e.g. target or gateway tokens which are valid for authenticates - * against SP. + * A singleton bean which holds the {@link SecurityTokenGenerator} and make it + * accessible to beans which are not managed by spring, e.g. JPA entities. */ -public class SecurityTokenGenerator { +@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. + * Generates a random secure token of {@link #TOKEN_LENGTH} bytes length as hexadecimal string. * * @return a new generated random alphanumeric string. */ - public String generateToken() { + public static String generateToken() { return new String(Hex.encode(SECURE_RANDOM.generateKey())); } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SecurityTokenGeneratorHolder.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SecurityTokenGeneratorHolder.java deleted file mode 100644 index 452cf5663..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SecurityTokenGeneratorHolder.java +++ /dev/null @@ -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(); - } -} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleManagement.java index 2b395405b..586489fbe 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeManagement.java index d69353088..6e16011f5 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleTypeManagement.java @@ -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; 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 dc7314eb4..5cf4a54ff 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 @@ -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 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); } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java index 7b92f028a..195500a8c 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetFilterQueryManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java index 1fdf3ad89..cf7249feb 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -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 : controllerId : builder.name; securityToken = ObjectUtils.isEmpty(builder.securityToken) - ? SecurityTokenGeneratorHolder.getInstance().generateToken() + ? SecurityTokenGenerator.generateToken() : builder.securityToken; } } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java index 32aa3f3be..9a7afb93d 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTypeManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTypeManagement.java index 09faa6850..8e411219d 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTypeManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTypeManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java index 58ff04beb..a06ea0f0b 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java index 0c6a36df8..97d6e40a6 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantStatsManagement.java @@ -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; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/UpdateMode.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/UpdateMode.java index 407cdb1ac..eef0fc3a2 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/UpdateMode.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/UpdateMode.java @@ -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. * diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/AbstractRemoteEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/AbstractRemoteEvent.java index 61503e170..403b4ff16 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/AbstractRemoteEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/AbstractRemoteEvent.java @@ -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") diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/TenantConfigurationDeletedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/TenantConfigurationDeletedEvent.java index 9fffbf7d7..b87323ea1 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/TenantConfigurationDeletedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/TenantConfigurationDeletedEvent.java @@ -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; /** diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/SystemSecurityContextHolder.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/SystemSecurityContextHolder.java deleted file mode 100644 index 348c06db4..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/SystemSecurityContextHolder.java +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/TenantConfigHelper.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/TenantConfigHelper.java new file mode 100644 index 000000000..c5d3a7e61 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/TenantConfigHelper.java @@ -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 getAsSystem(final String key, final Class 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 pollStatusResolver() { + return getTenantConfigurationManagement().pollStatusResolver(); + } +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/TenantConfigurationManagementHolder.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/TenantConfigurationManagementHolder.java deleted file mode 100644 index 5dddc651a..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/helper/TenantConfigurationManagementHolder.java +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Target.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Target.java index 43173aa15..85f7e0257 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Target.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Target.java @@ -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 { /** * @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(); diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/VirtualPropertyResolver.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/VirtualPropertyResolver.java index 9207b2f02..22c17c5b2 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/VirtualPropertyResolver.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/VirtualPropertyResolver.java @@ -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); } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java index f2da6ea60..57a20baac 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java @@ -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 */ diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/utils/TenantConfigHelper.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/utils/TenantConfigHelper.java deleted file mode 100644 index 59811874f..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/utils/TenantConfigHelper.java +++ /dev/null @@ -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 getConfigValue(final String key, final Class 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 pollStatusResolver() { - return tenantConfigurationManagement.pollStatusResolver(); - } -} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventPublisherConfiguration.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventPublisherConfiguration.java index d197cc0ce..fe96d9185 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventPublisherConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventPublisherConfiguration.java @@ -9,8 +9,11 @@ */ package org.eclipse.hawkbit.event; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; + import java.util.concurrent.Executor; import java.util.function.Consumer; + import io.protostuff.ProtostuffIOUtil; import io.protostuff.Schema; import lombok.extern.slf4j.Slf4j; @@ -19,7 +22,6 @@ import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent; import org.eclipse.hawkbit.repository.event.remote.RemoteTenantAwareEvent; import org.eclipse.hawkbit.repository.event.remote.service.AbstractServiceRemoteEvent; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -47,10 +49,9 @@ public class EventPublisherConfiguration { */ @Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME) ApplicationEventMulticaster applicationEventMulticaster( - @Qualifier("asyncExecutor") final Executor executor, - final SystemSecurityContext systemSecurityContext, final ApplicationEventFilter applicationEventFilter) { + @Qualifier("asyncExecutor") final Executor executor, final ApplicationEventFilter applicationEventFilter) { final SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = - new TenantAwareApplicationEventPublisher(systemSecurityContext, applicationEventFilter); + new TenantAwareApplicationEventPublisher(applicationEventFilter); simpleApplicationEventMulticaster.setTaskExecutor(executor); return simpleApplicationEventMulticaster; } @@ -76,17 +77,14 @@ public class EventPublisherConfiguration { private static class TenantAwareApplicationEventPublisher extends SimpleApplicationEventMulticaster { - private final SystemSecurityContext systemSecurityContext; private final ApplicationEventFilter applicationEventFilter; - protected TenantAwareApplicationEventPublisher( - final SystemSecurityContext systemSecurityContext, final ApplicationEventFilter applicationEventFilter) { - this.systemSecurityContext = systemSecurityContext; + protected TenantAwareApplicationEventPublisher(final ApplicationEventFilter applicationEventFilter) { this.applicationEventFilter = applicationEventFilter; } /** - * Was overridden that not every event has to run within an own tenantAware. + * Was overridden that not every event has to run within an own tenant. */ @Override public void multicastEvent(final ApplicationEvent event, final ResolvableType eventType) { @@ -95,19 +93,13 @@ public class EventPublisherConfiguration { } if (event instanceof final RemoteTenantAwareEvent remoteEvent) { - systemSecurityContext.runAsSystemAsTenant(() -> { - super.multicastEvent(event, eventType); - return null; - }, remoteEvent.getTenant()); + asSystemAsTenant(remoteEvent.getTenant(), () -> super.multicastEvent(event, eventType)); return; } if (event instanceof final AbstractServiceRemoteEvent serviceRemoteEvent && serviceRemoteEvent.getRemoteEvent() instanceof RemoteTenantAwareEvent tenantAwareEvent) { - systemSecurityContext.runAsSystemAsTenant(() -> { - super.multicastEvent(event, eventType); - return null; - }, tenantAwareEvent.getTenant()); + asSystemAsTenant(tenantAwareEvent.getTenant(), () -> super.multicastEvent(event, eventType)); return; } diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventType.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventType.java index f4178e037..ac3305161 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventType.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventType.java @@ -26,15 +26,6 @@ import org.eclipse.hawkbit.repository.event.remote.DistributionSetTypeDeletedEve import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent; import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent; import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent; -import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent; -import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent; -import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent; -import org.eclipse.hawkbit.repository.event.remote.service.MultiActionAssignServiceEvent; -import org.eclipse.hawkbit.repository.event.remote.service.MultiActionCancelServiceEvent; -import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistributionSetServiceEvent; -import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent; -import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent; -import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent; import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.RolloutGroupDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.RolloutStoppedEvent; @@ -74,6 +65,15 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationUpdatedEvent; +import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent; +import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent; +import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent; +import org.eclipse.hawkbit.repository.event.remote.service.MultiActionAssignServiceEvent; +import org.eclipse.hawkbit.repository.event.remote.service.MultiActionCancelServiceEvent; +import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistributionSetServiceEvent; +import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent; +import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent; +import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent; import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent; /** diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/RepositoryConfiguration.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/RepositoryConfiguration.java index d7c1db584..f73003636 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/RepositoryConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/RepositoryConfiguration.java @@ -12,8 +12,8 @@ package org.eclipse.hawkbit.repository; import java.util.Optional; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.im.authentication.Hierarchy; -import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions; +import org.eclipse.hawkbit.auth.Hierarchy; +import org.eclipse.hawkbit.auth.SpringEvalExpressions; import org.eclipse.hawkbit.tenancy.configuration.ControllerPollProperties; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.springframework.beans.factory.annotation.Value; @@ -47,8 +47,7 @@ public class RepositoryConfiguration { @Bean @ConditionalOnMissingBean - @SuppressWarnings("java:S3358") - // java:S3358 better readable this way + @SuppressWarnings("java:S3358") // java:S3358 better readable this way RoleHierarchy roleHierarchy( // if configured replaces the hierarchy completely @Value("${hawkbit.hierarchy:}") final String hierarchy, @@ -62,6 +61,9 @@ public class RepositoryConfiguration { @Bean PermissionEvaluator permissionEvaluator(final RoleHierarchy roleHierarchy) { + // sets up global access to the role hierarchy + Hierarchy.setRoleHierarchy(roleHierarchy); + // and returns a custom permission evaluator return new DenyAllPermissionEvaluator() { @Override @@ -72,7 +74,8 @@ public class RepositoryConfiguration { .replace(SpringEvalExpressions.PERMISSION_GROUP_PLACEHOLDER, permissionSupport.permissionGroup()); // do permissions check - final boolean hasPermission = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities()).stream() + final boolean hasPermission = Hierarchy.getRoleHierarchy() + .getReachableGrantedAuthorities(authentication.getAuthorities()).stream() .map(GrantedAuthority::getAuthority) .anyMatch(authority -> authority.equals(neededPermission)); if (!hasPermission) { diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/RolloutStatusCache.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/RolloutStatusCache.java index 9ec8004db..e6257a3d3 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/RolloutStatusCache.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/RolloutStatusCache.java @@ -9,6 +9,8 @@ */ package org.eclipse.hawkbit.repository; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; + import java.util.Collections; import java.util.List; import java.util.Map; @@ -25,7 +27,6 @@ import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus; import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.cache.Cache; import org.springframework.context.event.EventListener; @@ -39,19 +40,13 @@ public class RolloutStatusCache { private static final TenantAwareCacheManager CACHE_MANAGER = TenantAwareCacheManager.getInstance(); - private final TenantAware tenantAware; - - public RolloutStatusCache(final TenantAware tenantAware) { - this.tenantAware = tenantAware; - } - /** * Retrieves cached list of {@link TotalTargetCountActionStatus} of {@link Rollout}s. * * @param rollouts rolloutIds to retrieve cache entries for * @return map of cached entries */ - public Map> getRolloutStatus(final List rollouts) { + public static Map> getRolloutStatus(final List rollouts) { return retrieveFromCache(rollouts, getRolloutStatusCache()); } @@ -61,7 +56,7 @@ public class RolloutStatusCache { * @param rolloutId to retrieve cache entries for * @return map of cached entries */ - public List getRolloutStatus(final Long rolloutId) { + public static List getRolloutStatus(final Long rolloutId) { return retrieveFromCache(rolloutId, getRolloutStatusCache()); } @@ -71,7 +66,7 @@ public class RolloutStatusCache { * @param rolloutGroups rolloutGroupsIds to retrieve cache entries for * @return map of cached entries */ - public Map> getRolloutGroupStatus(final List rolloutGroups) { + public static Map> getRolloutGroupStatus(final List rolloutGroups) { return retrieveFromCache(rolloutGroups, getGroupStatusCache()); } @@ -81,7 +76,7 @@ public class RolloutStatusCache { * @param groupId to retrieve cache entries for * @return map of cached entries */ - public List getRolloutGroupStatus(final Long groupId) { + public static List getRolloutGroupStatus(final Long groupId) { return retrieveFromCache(groupId, getGroupStatusCache()); } @@ -91,7 +86,7 @@ public class RolloutStatusCache { * * @param put map of cached entries */ - public void putRolloutStatus(final Map> put) { + public static void putRolloutStatus(final Map> put) { putIntoCache(put, getRolloutStatusCache()); } @@ -101,7 +96,7 @@ public class RolloutStatusCache { * @param rolloutId the cache entries belong to * @param status list to cache */ - public void putRolloutStatus(final Long rolloutId, final List status) { + public static void putRolloutStatus(final Long rolloutId, final List status) { putIntoCache(rolloutId, status, getRolloutStatusCache()); } @@ -110,7 +105,7 @@ public class RolloutStatusCache { * * @param put map of cached entries */ - public void putRolloutGroupStatus(final Map> put) { + public static void putRolloutGroupStatus(final Map> put) { putIntoCache(put, getGroupStatusCache()); } @@ -120,51 +115,51 @@ public class RolloutStatusCache { * @param groupId the cache entries belong to * @param status list to cache */ - public void putRolloutGroupStatus(final Long groupId, final List status) { + public static void putRolloutGroupStatus(final Long groupId, final List status) { putIntoCache(groupId, status, getGroupStatusCache()); } @EventListener(classes = AbstractActionEvent.class) public void invalidateCachedTotalTargetCountActionStatus(final AbstractActionEvent event) { if (event.getRolloutId() != null) { - final Cache cache = tenantAware.runAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_RO_NAME)); + final Cache cache = asSystemAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_RO_NAME)); cache.evict(event.getRolloutId()); } if (event.getRolloutGroupId() != null) { - final Cache cache = tenantAware.runAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_GR_NAME)); + final Cache cache = asSystemAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_GR_NAME)); cache.evict(event.getRolloutGroupId()); } } @EventListener(classes = RolloutDeletedEvent.class) public void invalidateCachedTotalTargetCountOnRolloutDelete(final RolloutDeletedEvent event) { - final Cache cache = tenantAware.runAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_RO_NAME)); + final Cache cache = asSystemAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_RO_NAME)); cache.evict(event.getEntityId()); } @EventListener(classes = RolloutGroupDeletedEvent.class) public void invalidateCachedTotalTargetCountOnRolloutGroupDelete(final RolloutGroupDeletedEvent event) { - final Cache cache = tenantAware.runAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_GR_NAME)); + final Cache cache = asSystemAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_GR_NAME)); cache.evict(event.getEntityId()); } @EventListener(classes = RolloutStoppedEvent.class) public void invalidateCachedTotalTargetCountOnRolloutStopped(final RolloutStoppedEvent event) { - final Cache cache = tenantAware.runAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_RO_NAME)); + final Cache cache = asSystemAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_RO_NAME)); cache.evict(event.getRolloutId()); event.getRolloutGroupIds().forEach( - groupId -> tenantAware.runAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_GR_NAME)).evict(groupId)); + groupId -> asSystemAsTenant(event.getTenant(), () -> CACHE_MANAGER.getCache(CACHE_GR_NAME)).evict(groupId)); } - private @NotNull Map> retrieveFromCache(final List ids, @NotNull final Cache cache) { + private static @NotNull Map> retrieveFromCache(final List ids, @NotNull final Cache cache) { return ids.stream() .map(id -> cache.get(id, CachedTotalTargetCountActionStatus.class)) .filter(Objects::nonNull) .collect(Collectors.toMap(CachedTotalTargetCountActionStatus::id, CachedTotalTargetCountActionStatus::status)); } - private List retrieveFromCache(final Long id, @NotNull final Cache cache) { + private static List retrieveFromCache(final Long id, @NotNull final Cache cache) { final CachedTotalTargetCountActionStatus cacheItem = cache.get(id, CachedTotalTargetCountActionStatus.class); if (cacheItem == null) { return Collections.emptyList(); @@ -172,20 +167,19 @@ public class RolloutStatusCache { return cacheItem.status(); } - private void putIntoCache(final Long id, final List status, - @NotNull final Cache cache) { + private static void putIntoCache(final Long id, final List status, @NotNull final Cache cache) { cache.put(id, new CachedTotalTargetCountActionStatus(id, status)); } - private void putIntoCache(final Map> put, @NotNull final Cache cache) { + private static void putIntoCache(final Map> put, @NotNull final Cache cache) { put.forEach((k, v) -> cache.put(k, new CachedTotalTargetCountActionStatus(k, v))); } - private @NotNull Cache getRolloutStatusCache() { + private static @NotNull Cache getRolloutStatusCache() { return Objects.requireNonNull(CACHE_MANAGER.getCache(CACHE_RO_NAME), "Cache '" + CACHE_RO_NAME + "' is null!"); } - private @NotNull Cache getGroupStatusCache() { + private static @NotNull Cache getGroupStatusCache() { return Objects.requireNonNull(CACHE_MANAGER.getCache(CACHE_GR_NAME), "Cache '" + CACHE_RO_NAME + "' is null!"); } diff --git a/hawkbit-repository/hawkbit-repository-core/src/test/java/org/eclipse/hawkbit/event/AbstractEventMessageConverterTest.java b/hawkbit-repository/hawkbit-repository-core/src/test/java/org/eclipse/hawkbit/event/AbstractEventMessageConverterTest.java index 83cba85b4..74221541c 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/test/java/org/eclipse/hawkbit/event/AbstractEventMessageConverterTest.java +++ b/hawkbit-repository/hawkbit-repository-core/src/test/java/org/eclipse/hawkbit/event/AbstractEventMessageConverterTest.java @@ -9,6 +9,11 @@ */ package org.eclipse.hawkbit.event; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.util.HashMap; + import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent; import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent; @@ -22,18 +27,12 @@ import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceE import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Target; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.converter.MessageConverter; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; - -import java.util.HashMap; - abstract class AbstractEventMessageConverterTest { protected final MessageConverter messageConverter; diff --git a/hawkbit-repository/hawkbit-repository-jpa-api/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantAwareHolder.java b/hawkbit-repository/hawkbit-repository-jpa-api/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantAwareHolder.java deleted file mode 100644 index 562e5bcbf..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa-api/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/TenantAwareHolder.java +++ /dev/null @@ -1,47 +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.jpa.model.helper; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * A singleton bean which holds {@link TenantAware} 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 TenantAwareHolder { - - private static final TenantAwareHolder SINGLETON = new TenantAwareHolder(); - - private TenantAware tenantAware; - - /** - * @return the singleton {@link TenantAwareHolder} instance - */ - public static TenantAwareHolder getInstance() { - return SINGLETON; - } - - @Autowired // spring setter injection - public void setTenantAware(final TenantAware tenantAware) { - this.tenantAware = tenantAware; - } - - /** - * @return the {@link TenantAware} service - */ - public TenantAware getTenantAware() { - return tenantAware; - } -} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/Jpa.java b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/Jpa.java index 06eb2a5fa..d00a3f7af 100644 --- a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/Jpa.java +++ b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/Jpa.java @@ -11,7 +11,6 @@ package org.eclipse.hawkbit.repository.jpa; import java.util.Collection; import java.util.Iterator; -import java.util.List; import java.util.stream.IntStream; import jakarta.persistence.Query; diff --git a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaConfiguration.java index 49007c814..283481ee2 100644 --- a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaConfiguration.java @@ -15,7 +15,6 @@ import java.util.Map; import javax.sql.DataSource; import lombok.Data; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.persistence.config.PersistenceUnitProperties; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; @@ -45,7 +44,6 @@ public class JpaConfiguration extends JpaBaseConfiguration { private final Map eclipselink = new HashMap<>(); } - private final TenantAware.TenantResolver tenantResolver; // only for testing purposes ddl generation may be enabled private final Map eclipselinkProperties; @@ -53,10 +51,8 @@ public class JpaConfiguration extends JpaBaseConfiguration { protected JpaConfiguration( final DataSource dataSource, final JpaProperties properties, final ObjectProvider jtaTransactionManagerProvider, - final TenantAware.TenantResolver tenantResolver, final Properties eclipselinkProperties) { super(dataSource, properties, jtaTransactionManagerProvider); - this.tenantResolver = tenantResolver; this.eclipselinkProperties = eclipselinkProperties.getEclipselink(); } @@ -67,7 +63,7 @@ public class JpaConfiguration extends JpaBaseConfiguration { @Override @Bean public PlatformTransactionManager transactionManager(final ObjectProvider transactionManagerCustomizers) { - return new TransactionManager(tenantResolver); + return new TransactionManager(); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/TransactionManager.java b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/TransactionManager.java index d069be7ab..efd018cf7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/TransactionManager.java +++ b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/TransactionManager.java @@ -15,9 +15,9 @@ import java.util.Objects; import jakarta.persistence.EntityManager; import jakarta.transaction.Transaction; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.jpa.model.EntityPropertyChangeListener; import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.persistence.config.PersistenceUnitProperties; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.descriptors.DescriptorEventManager; @@ -29,7 +29,7 @@ import org.springframework.transaction.support.DefaultTransactionStatus; import org.springframework.transaction.support.TransactionSynchronizationManager; /** - * {@link org.springframework.orm.jpa.JpaTransactionManager} that sets the {@link TenantAware#getCurrentTenant()} in the eclipselink session. This has + * {@link org.springframework.orm.jpa.JpaTransactionManager} that sets the {@link AccessContext#tenant()} in the eclipselink session. This has * to be done in eclipselink after a {@link Transaction} has been started. *

* The class also handles setting: @@ -45,8 +45,6 @@ class TransactionManager extends JpaTransactionManager { private static final Class JPA_TARGET; - private transient TenantAware.TenantResolver tenantResolver; - static { try { JPA_TARGET = Class.forName("org.eclipse.hawkbit.repository.jpa.model.JpaTarget"); @@ -57,10 +55,6 @@ class TransactionManager extends JpaTransactionManager { } } - TransactionManager(final TenantAware.TenantResolver tenantResolver) { - this.tenantResolver = tenantResolver; - } - private static final EntityPropertyChangeListener ENTITY_PROPERTY_CHANGE_LISTENER = new EntityPropertyChangeListener(); @Override @@ -83,7 +77,7 @@ class TransactionManager extends JpaTransactionManager { } } - final String currentTenant = tenantResolver.resolveTenant(); + final String currentTenant = AccessContext.tenant(); if (currentTenant == null) { cleanupTenant(em); } else { diff --git a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java index 4b59da01a..be9805785 100644 --- a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java @@ -22,8 +22,8 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.exception.TenantNotExistException; -import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.eclipse.persistence.annotations.Multitenant; import org.eclipse.persistence.annotations.MultitenantType; @@ -50,7 +50,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn private String tenant; /** - * Tenant aware entities extend the equals/hashcode strategy with the tenant name. That would allow for instance in a + * AccessContext aware entities extend the equals/hashcode strategy with the tenant name. That would allow for instance in a * multi-schema based data separation setup to have the same primary key for different entities of different tenants. */ @Override @@ -59,7 +59,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn } /** - * Tenant aware entities extend the equals/hashcode strategy with the tenant name. That would allow for instance in a + * AccessContext aware entities extend the equals/hashcode strategy with the tenant name. That would allow for instance in a * multi-schema based data separation setup to have the same primary key for different entities of * different tenants. */ @@ -86,13 +86,13 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn */ @PrePersist void prePersist() { - // before persisting the entity check the current ID of the tenant by using the TenantAware service - final String currentTenant = TenantAwareHolder.getInstance().getTenantAware().getCurrentTenant(); + // before persisting the entity check the current ID of the tenant by using the AccessContext + final String currentTenant = AccessContext.tenant(); if (currentTenant == null) { throw new TenantNotExistException( String.format( - "Tenant %s does not exists, cannot create entity %s with id %d", - TenantAwareHolder.getInstance().getTenantAware().getCurrentTenant(), getClass(), getId())); + "AccessContext %s does not exists, cannot create entity %s with id %d", + AccessContext.tenant(), getClass(), getId())); } setTenant(currentTenant.toUpperCase()); } diff --git a/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/Jpa.java b/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/Jpa.java index aca3dcd14..cdf22d4d0 100644 --- a/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/Jpa.java +++ b/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/Jpa.java @@ -10,7 +10,6 @@ package org.eclipse.hawkbit.repository.jpa; import java.util.Collection; -import java.util.List; import jakarta.persistence.Query; diff --git a/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaConfiguration.java index d095c5ace..b232c3bbf 100644 --- a/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaConfiguration.java @@ -13,12 +13,12 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import javax.sql.DataSource; + import lombok.Data; import org.eclipse.hawkbit.repository.jpa.model.EntityPropertyChangeListener; - import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper; import org.eclipse.hawkbit.repository.jpa.utils.JpaExceptionTranslator; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.hibernate.boot.Metadata; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.cfg.MultiTenancySettings; @@ -41,13 +41,10 @@ import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; import org.springframework.orm.jpa.vendor.HibernateJpaDialect; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; -import org.springframework.security.core.parameters.P; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.transaction.support.DefaultTransactionStatus; -import javax.sql.DataSource; - /** * General Hibernate configuration for hawkBit's Repository. */ @@ -68,10 +65,9 @@ public class JpaConfiguration extends JpaBaseConfiguration { protected JpaConfiguration( final DataSource dataSource, final JpaProperties properties, final ObjectProvider jtaTransactionManagerProvider, - final TenantAware.TenantResolver tenantResolver, final Properties hibernateProperties) { super(dataSource, properties, jtaTransactionManagerProvider); - tenantIdentifier = new TenantIdentifier(tenantResolver); + tenantIdentifier = new TenantIdentifier(); this.hibernateProperties = hibernateProperties.getHibernate(); } diff --git a/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantIdentifier.java b/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantIdentifier.java index 2e48a8c05..4b2e10ff7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantIdentifier.java +++ b/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantIdentifier.java @@ -11,26 +11,20 @@ package org.eclipse.hawkbit.repository.jpa; import java.util.Optional; -import org.eclipse.hawkbit.tenancy.TenantAware; +import org.eclipse.hawkbit.context.AccessContext; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; /** * {@link CurrentTenantIdentifierResolver} and {@link HibernatePropertiesCustomizer} that resolves the - * {@link TenantAware#getCurrentTenant()} for hibernate. + * {@link AccessContext#tenant()} for hibernate. */ class TenantIdentifier implements CurrentTenantIdentifierResolver { - private final TenantAware.TenantResolver tenantResolver; - - TenantIdentifier(final TenantAware.TenantResolver tenantResolver) { - this.tenantResolver = tenantResolver; - } - @Override public String resolveCurrentTenantIdentifier() { // on bootstrapping hibernate requests tenant and want to be non-null - return Optional.ofNullable(tenantResolver.resolveTenant()).map(String::toUpperCase).orElse(""); + return Optional.ofNullable(AccessContext.tenant()).map(String::toUpperCase).orElse(""); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java b/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java index 67c0f1f09..906b20bbf 100644 --- a/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa-hibernate/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaTenantAwareBaseEntity.java @@ -22,8 +22,8 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.exception.TenantNotExistException; -import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.hibernate.annotations.TenantId; @@ -46,7 +46,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn private String tenant; /** - * Tenant aware entities extend the equals/hashcode strategy with the tenant name. That would allow for instance in a + * AccessContext aware entities extend the equals/hashcode strategy with the tenant name. That would allow for instance in a * multi-schema based data separation setup to have the same primary key for different entities of different tenants. */ @Override @@ -55,7 +55,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn } /** - * Tenant aware entities extend the equals/hashcode strategy with the tenant name. That would allow for instance in a + * AccessContext aware entities extend the equals/hashcode strategy with the tenant name. That would allow for instance in a * multi-schema based data separation setup to have the same primary key for different entities of * different tenants. */ @@ -82,13 +82,13 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn */ @PrePersist void prePersist() { - // before persisting the entity check the current ID of the tenant by using the TenantAware service - final String currentTenant = TenantAwareHolder.getInstance().getTenantAware().getCurrentTenant(); + // before persisting the entity check the current ID of the tenant by using the AccessContext + final String currentTenant = AccessContext.tenant(); if (currentTenant == null) { throw new TenantNotExistException( String.format( - "Tenant %s does not exists, cannot create entity %s with id %d", - TenantAwareHolder.getInstance().getTenantAware().getCurrentTenant(), getClass(), getId())); + "AccessContext %s does not exists, cannot create entity %s with id %d", + AccessContext.tenant(), getClass(), getId())); } setTenant(currentTenant.toUpperCase()); } 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 ff4473539..0e8019998 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 @@ -11,11 +11,12 @@ package org.eclipse.hawkbit.repository.jpa; import java.util.Collection; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.repository.RolloutApprovalStrategy; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -26,34 +27,19 @@ import org.springframework.security.core.context.SecurityContextHolder; * as the roles of the user who created the Rollout. Provides a no-operation implementation of * {@link RolloutApprovalStrategy#onApprovalRequired(Rollout)}. */ +@NoArgsConstructor(access = AccessLevel.PACKAGE) public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy { - private final TenantConfigurationManagement tenantConfigurationManagement; - - private final SystemSecurityContext systemSecurityContext; - - DefaultRolloutApprovalStrategy( - final TenantConfigurationManagement tenantConfigurationManagement, - final SystemSecurityContext systemSecurityContext) { - this.tenantConfigurationManagement = tenantConfigurationManagement; - this.systemSecurityContext = systemSecurityContext; - } - /** - * Returns true, if rollout approval is enabled and rollout creator doesn't have approval role. It have to be called in the user context + * Returns true, if rollout approval is enabled and rollout creator doesn't have approval role. It has to be called in the user context */ @Override public boolean isApprovalNeeded(final Rollout rollout) { - return isApprovalEnabled() && hasNoApproveRolloutPermission( - getCurrentAuthentication().getAuthorities().stream().map(GrantedAuthority::getAuthority).toList()); + return TenantConfigHelper.getAsSystem(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class) && + hasNoApproveRolloutPermission( + getCurrentAuthentication().getAuthorities().stream().map(GrantedAuthority::getAuthority).toList()); } - /*** - * Per default do nothing. - * - * @param rollout - * rollout to create approval task for. - */ @Override public void onApprovalRequired(final Rollout rollout) { // do nothing per default, can be extended by further implementations. @@ -71,9 +57,4 @@ public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy { private static boolean hasNoApproveRolloutPermission(final Collection authorities) { return authorities.stream().noneMatch(SpPermission.APPROVE_ROLLOUT::equals); } - - private boolean isApprovalEnabled() { - return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement - .getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue()); - } } \ 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 b47d3bc05..9a7e6b70e 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 @@ -39,15 +39,12 @@ import org.eclipse.hawkbit.repository.RolloutExecutor; import org.eclipse.hawkbit.repository.RolloutHandler; import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.RolloutStatusCache; -import org.eclipse.hawkbit.repository.SecurityTokenGeneratorHolder; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.event.ApplicationEventFilter; import org.eclipse.hawkbit.repository.event.remote.EventEntityManager; import org.eclipse.hawkbit.repository.event.remote.EventEntityManagerHolder; import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent; -import org.eclipse.hawkbit.repository.helper.SystemSecurityContextHolder; -import org.eclipse.hawkbit.repository.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.repository.jpa.acm.AccessController; import org.eclipse.hawkbit.repository.jpa.aspects.ExceptionMappingAspectHandler; import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoActionCleanup; @@ -64,7 +61,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType; import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder; -import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ArtifactRepository; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository; @@ -82,7 +78,6 @@ import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRollou import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition; import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition; import org.eclipse.hawkbit.repository.jpa.scheduler.AutoAssignScheduler; -import org.eclipse.hawkbit.repository.jpa.scheduler.JpaAutoAssignExecutor; import org.eclipse.hawkbit.repository.jpa.scheduler.JpaRolloutHandler; import org.eclipse.hawkbit.repository.jpa.scheduler.RolloutScheduler; import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper; @@ -90,9 +85,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver; 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.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -222,17 +214,15 @@ public class JpaRepositoryConfiguration { @Bean @ConditionalOnMissingBean PauseRolloutGroupAction pauseRolloutGroupAction( - final RolloutManagement rolloutManagement, final RolloutGroupRepository rolloutGroupRepository, - final SystemSecurityContext systemSecurityContext) { - return new PauseRolloutGroupAction(rolloutManagement, rolloutGroupRepository, systemSecurityContext); + final RolloutManagement rolloutManagement, final RolloutGroupRepository rolloutGroupRepository) { + return new PauseRolloutGroupAction(rolloutManagement, rolloutGroupRepository); } @Bean @ConditionalOnMissingBean StartNextGroupRolloutGroupSuccessAction startNextRolloutGroupAction( - final RolloutGroupRepository rolloutGroupRepository, final DeploymentManagement deploymentManagement, - final SystemSecurityContext systemSecurityContext) { - return new StartNextGroupRolloutGroupSuccessAction(rolloutGroupRepository, deploymentManagement, systemSecurityContext); + final RolloutGroupRepository rolloutGroupRepository, final DeploymentManagement deploymentManagement) { + return new StartNextGroupRolloutGroupSuccessAction(rolloutGroupRepository, deploymentManagement); } @Bean @@ -260,8 +250,8 @@ public class JpaRepositoryConfiguration { @Bean @ConditionalOnMissingBean - SystemManagementCacheKeyGenerator systemManagementCacheKeyGenerator(final TenantAware tenantAware) { - return new SystemManagementCacheKeyGenerator(tenantAware); + SystemManagementCacheKeyGenerator systemManagementCacheKeyGenerator() { + return new SystemManagementCacheKeyGenerator(); } @Bean @@ -270,10 +260,10 @@ public class JpaRepositoryConfiguration { return new PropertiesQuotaManagement(securityProperties); } + // register as bean in order to be registered event listeners @Bean - @ConditionalOnMissingBean - RolloutStatusCache rolloutStatusCache(final TenantAware tenantAware) { - return new RolloutStatusCache(tenantAware); + RolloutStatusCache rolloutStatusCache() { + return new RolloutStatusCache(); } @Bean @@ -282,46 +272,6 @@ public class JpaRepositoryConfiguration { return e -> e instanceof TargetPollEvent && !repositoryProperties.isPublishTargetPollEvent(); } - /** - * @return the {@link SystemSecurityContext} singleton bean which make it - * accessible in beans which cannot access the service directly, e.g. - * JPA entities. - */ - @Bean - SystemSecurityContextHolder systemSecurityContextHolder() { - return SystemSecurityContextHolder.getInstance(); - } - - /** - * @return the {@link TenantConfigurationManagement} singleton bean which make - * it accessible in beans which cannot access the service directly, e.g. - * JPA entities. - */ - @Bean - TenantConfigurationManagementHolder tenantConfigurationManagementHolder() { - return TenantConfigurationManagementHolder.getInstance(); - } - - /** - * @return the {@link TenantAwareHolder} singleton bean which holds the current - * {@link TenantAware} service and make it accessible in beans which - * cannot access the service directly, e.g. JPA entities. - */ - @Bean - TenantAwareHolder tenantAwareHolder() { - return TenantAwareHolder.getInstance(); - } - - /** - * @return the {@link SecurityTokenGeneratorHolder} singleton bean which holds - * the current {@link SecurityTokenGenerator} service and make it - * accessible in beans which cannot access the service via injection - */ - @Bean - SecurityTokenGeneratorHolder securityTokenGeneratorHolder() { - return SecurityTokenGeneratorHolder.getInstance(); - } - /** * @return the singleton instance of the {@link EntityInterceptorHolder} */ @@ -340,10 +290,10 @@ public class JpaRepositoryConfiguration { @Bean @ConditionalOnMissingBean - RolloutHandler rolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement, + RolloutHandler rolloutHandler(final RolloutManagement rolloutManagement, final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry, final PlatformTransactionManager txManager, final Optional meterRegistry) { - return new JpaRolloutHandler(tenantAware, rolloutManagement, rolloutExecutor, lockRegistry, txManager, meterRegistry); + return new JpaRolloutHandler(rolloutManagement, rolloutExecutor, lockRegistry, txManager, meterRegistry); } /** @@ -353,9 +303,8 @@ public class JpaRepositoryConfiguration { */ @Bean @ConditionalOnMissingBean - RolloutApprovalStrategy rolloutApprovalStrategy( - final TenantConfigurationManagement tenantConfigurationManagement, final SystemSecurityContext systemSecurityContext) { - return new DefaultRolloutApprovalStrategy(tenantConfigurationManagement, systemSecurityContext); + RolloutApprovalStrategy rolloutApprovalStrategy() { + return new DefaultRolloutApprovalStrategy(); } /** @@ -372,44 +321,36 @@ public class JpaRepositoryConfiguration { /** * {@link EventEntityManager} bean. * - * @param aware the tenant aware * @param entityManager the entity manager * @return a new {@link EventEntityManager} */ @Bean @ConditionalOnMissingBean - EventEntityManager eventEntityManager(final TenantAware aware, final EntityManager entityManager) { - return new JpaEventEntityManager(aware, entityManager); + EventEntityManager eventEntityManager(final EntityManager entityManager) { + return new JpaEventEntityManager(entityManager); } /** * {@link AutoAssignScheduler} bean. *

- * Note: does not activate in test profile, otherwise it is hard to test the - * auto assign functionality. - * - * @param systemManagement to find all tenants - * @param systemSecurityContext to run as system - * @param autoAssignExecutor to run a check as tenant - * @param lockRegistry to lock the tenant for auto assignment - * @return a new {@link JpaAutoAssignExecutor} + * Note: does not activate in test profile, otherwise it is hard to test the auto assign functionality. */ @Bean @ConditionalOnMissingBean // don't active the auto assign scheduler in test, otherwise it is hard to test @Profile("!test") @ConditionalOnProperty(prefix = "hawkbit.autoassign.scheduler", name = "enabled", matchIfMissing = true) - AutoAssignScheduler autoAssignScheduler(final SystemManagement systemManagement, - final SystemSecurityContext systemSecurityContext, final AutoAssignExecutor autoAssignExecutor, + AutoAssignScheduler autoAssignScheduler( + final SystemManagement systemManagement, final AutoAssignExecutor autoAssignExecutor, final LockRegistry lockRegistry, final Optional meterRegistry) { - return new AutoAssignScheduler(systemManagement, systemSecurityContext, autoAssignExecutor, lockRegistry, meterRegistry); + return new AutoAssignScheduler(systemManagement, autoAssignExecutor, lockRegistry, meterRegistry); } /** * {@link AutoActionCleanup} bean. * * @param deploymentManagement Deployment management service - * @param configManagement Tenant configuration service + * @param configManagement AccessContext configuration service * @return a new {@link AutoActionCleanup} bean */ @Bean @@ -418,44 +359,29 @@ public class JpaRepositoryConfiguration { return new AutoActionCleanup(deploymentManagement, configManagement); } - /** - * {@link AutoCleanupScheduler} bean. - * - * @param systemManagement to find all tenants - * @param systemSecurityContext to run as system - * @param lockRegistry to lock the tenant for auto assignment - * @param cleanupTasks a list of cleanup tasks - * @return a new {@link AutoCleanupScheduler} bean - */ @Bean @ConditionalOnMissingBean @Profile("!test") @ConditionalOnProperty(prefix = "hawkbit.autocleanup.scheduler", name = "enabled", matchIfMissing = true) AutoCleanupScheduler autoCleanupScheduler( final List cleanupTasks, - final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext, final LockRegistry lockRegistry) { - return new AutoCleanupScheduler(cleanupTasks, systemManagement, systemSecurityContext, lockRegistry); + final SystemManagement systemManagement, final LockRegistry lockRegistry) { + return new AutoCleanupScheduler(cleanupTasks, systemManagement, lockRegistry); } /** * {@link RolloutScheduler} bean. *

- * Note: does not activate in test profile, otherwise it is hard to test the - * rollout handling functionality. - * - * @param systemManagement to find all tenants - * @param rolloutHandler to run the rollout handler - * @param systemSecurityContext to run as system - * @return a new {@link RolloutScheduler} bean. + * Note: does not activate in test profile, otherwise it is hard to test the rollout handling functionality. */ @Bean @ConditionalOnMissingBean @Profile("!test") @ConditionalOnProperty(prefix = "hawkbit.rollout.scheduler", name = "enabled", matchIfMissing = true) RolloutScheduler rolloutScheduler( - final SystemManagement systemManagement, final RolloutHandler rolloutHandler, final SystemSecurityContext systemSecurityContext, + final SystemManagement systemManagement, final RolloutHandler rolloutHandler, @Value("${hawkbit.rollout.executor.thread-pool.size:1}") final int threadPoolSize, final Optional meterRegistry) { - return new RolloutScheduler(rolloutHandler, systemManagement, systemSecurityContext, threadPoolSize, meterRegistry); + return new RolloutScheduler(rolloutHandler, systemManagement, threadPoolSize, meterRegistry); } @Bean diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java index 29aadec66..5a7a04639 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java @@ -15,7 +15,8 @@ import java.util.Optional; import jakarta.validation.constraints.NotNull; -import org.eclipse.hawkbit.tenancy.TenantAware; +import lombok.NonNull; +import org.eclipse.hawkbit.context.AccessContext; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.cache.interceptor.SimpleKeyGenerator; import org.springframework.context.annotation.Bean; @@ -26,11 +27,6 @@ import org.springframework.context.annotation.Bean; public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyGenerator { private final ThreadLocal createInitialTenant = new ThreadLocal<>(); - private final TenantAware tenantAware; - - public SystemManagementCacheKeyGenerator(final TenantAware tenantAware) { - this.tenantAware = tenantAware; - } @Override @Bean @@ -70,16 +66,19 @@ public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyG /** * An implementation of the {@link KeyGenerator} to generate a key based on * either the {@code createInitialTenant} thread local and the - * {@link TenantAware}, but in case we are in a tenant creation with its default + * {@link AccessContext}, but in case we are in a tenant creation with its default * types we need to use as the tenant the current tenant which is currently - * created and not the one currently in the {@link TenantAware}. + * created and not the one currently in the {@link AccessContext}. */ public class CurrentTenantKeyGenerator implements KeyGenerator { @Override - public Object generate(final Object target, final Method method, final Object... params) { - String tenant = getTenantInCreation().orElseGet(tenantAware::getCurrentTenant).toUpperCase(); + public Object generate(@NonNull final Object target, @NonNull final Method method, @NonNull final Object... params) { + final String tenant = Objects.requireNonNull( + getTenantInCreation().orElseGet(AccessContext::tenant), + "CurrentTenantKeyGenerator.generate called not in tenant context") + .toUpperCase(); return SimpleKeyGenerator.generateKey(tenant, tenant); } } -} +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantKeyGenerator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantKeyGenerator.java index 18742fb76..611f5b898 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantKeyGenerator.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantKeyGenerator.java @@ -10,8 +10,9 @@ package org.eclipse.hawkbit.repository.jpa; import java.lang.reflect.Method; +import java.util.Objects; -import org.eclipse.hawkbit.tenancy.TenantAware; +import org.eclipse.hawkbit.context.AccessContext; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.stereotype.Service; @@ -21,14 +22,11 @@ import org.springframework.stereotype.Service; @Service public class TenantKeyGenerator implements KeyGenerator { - private final TenantAware tenantAware; - - public TenantKeyGenerator(final TenantAware tenantAware) { - this.tenantAware = tenantAware; - } - @Override public Object generate(final Object target, final Method method, final Object... params) { - return tenantAware.getCurrentTenant().toUpperCase(); + return Objects.requireNonNull( + AccessContext.tenant(), + "TenantKeyGenerator.generate called not in tenant context") + .toUpperCase(); } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/AccessControllerConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/AccessControllerConfiguration.java index 114ac116e..a245e517e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/AccessControllerConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/AccessControllerConfiguration.java @@ -21,13 +21,7 @@ import jakarta.persistence.criteria.Root; import jakarta.persistence.metamodel.EntityType; import org.aopalliance.intercept.MethodInvocation; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.repository.qfields.DistributionSetFields; -import org.eclipse.hawkbit.repository.qfields.DistributionSetTypeFields; -import org.eclipse.hawkbit.repository.qfields.SoftwareModuleFields; -import org.eclipse.hawkbit.repository.qfields.SoftwareModuleTypeFields; -import org.eclipse.hawkbit.repository.qfields.TargetFields; -import org.eclipse.hawkbit.repository.qfields.TargetTypeFields; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaAction_; @@ -37,8 +31,12 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType; -import org.eclipse.hawkbit.security.SecurityContextSerializer; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.eclipse.hawkbit.repository.qfields.DistributionSetFields; +import org.eclipse.hawkbit.repository.qfields.DistributionSetTypeFields; +import org.eclipse.hawkbit.repository.qfields.SoftwareModuleFields; +import org.eclipse.hawkbit.repository.qfields.SoftwareModuleTypeFields; +import org.eclipse.hawkbit.repository.qfields.TargetFields; +import org.eclipse.hawkbit.repository.qfields.TargetTypeFields; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -60,12 +58,6 @@ import org.springframework.util.function.SingletonSupplier; @ConditionalOnProperty(name = "hawkbit.acm.access-controller.enabled", havingValue = "true") public class AccessControllerConfiguration { - @Bean - @ConditionalOnMissingBean - SecurityContextSerializer securityContextSerializer() { - return SecurityContextSerializer.JSON_SERIALIZATION; - } - @Bean @ConditionalOnProperty(name = "hawkbit.acm.access-controller.target.enabled", havingValue = "true", matchIfMissing = true) AccessController targetAccessController() { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/AuthorityChecker.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/AuthorityChecker.java index 4efd9c659..33e00f415 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/AuthorityChecker.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/AuthorityChecker.java @@ -13,7 +13,7 @@ import java.util.Set; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.ql.jpa.QLSupport; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessController.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessController.java index 85f2aba05..24bda3077 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessController.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessController.java @@ -18,10 +18,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ql.QueryField; import org.eclipse.hawkbit.ql.jpa.QLSupport; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.springframework.data.jpa.domain.Specification; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; @@ -48,7 +48,7 @@ public class DefaultAccessController & QueryField, T> implemen @Override public Optional> getAccessRules(final Operation operation) { - if (SystemSecurityContext.isCurrentThreadSystemCode()) { + if (AccessContext.isCurrentThreadSystemCode()) { // system code - no restrictions. this runs with SYSTEM_ROLE, so no restrictions apply anyway - not scopes, but this way should be faster return Optional.empty(); } @@ -63,7 +63,7 @@ public class DefaultAccessController & QueryField, T> implemen @Override public void assertOperationAllowed(final Operation operation, final T entity) throws InsufficientPermissionException { - if (SystemSecurityContext.isCurrentThreadSystemCode()) { + if (AccessContext.isCurrentThreadSystemCode()) { // system code - no restrictions. this runs with SYSTEM_ROLE, so no restrictions apply anyway - not scopes, but this way should be faster return; } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoCleanupScheduler.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoCleanupScheduler.java index 4aef14b73..c5b3e4aee 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoCleanupScheduler.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoCleanupScheduler.java @@ -9,12 +9,13 @@ */ package org.eclipse.hawkbit.repository.jpa.autocleanup; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; + import java.util.List; import java.util.concurrent.locks.Lock; import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.SystemManagement; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.springframework.integration.support.locks.LockRegistry; import org.springframework.scheduling.annotation.Scheduled; @@ -29,7 +30,6 @@ public class AutoCleanupScheduler { private static final String PROP_AUTO_CLEANUP_INTERVAL = "${hawkbit.autocleanup.scheduler.fixedDelay:86400000}"; private final SystemManagement systemManagement; - private final SystemSecurityContext systemSecurityContext; private final LockRegistry lockRegistry; private final List cleanupTasks; @@ -38,14 +38,12 @@ public class AutoCleanupScheduler { * * @param cleanupTasks A list of cleanup tasks. * @param systemManagement Management APIs to invoke actions in a certain tenant context. - * @param systemSecurityContext The system security context. * @param lockRegistry A registry for shared locks. */ public AutoCleanupScheduler( final List cleanupTasks, - final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext, final LockRegistry lockRegistry) { + final SystemManagement systemManagement, final LockRegistry lockRegistry) { this.systemManagement = systemManagement; - this.systemSecurityContext = systemSecurityContext; this.lockRegistry = lockRegistry; this.cleanupTasks = cleanupTasks; } @@ -58,7 +56,7 @@ public class AutoCleanupScheduler { log.debug("Auto cleanup scheduler has been triggered."); // run this code in system code privileged to have the necessary permission to query and create entities if (!cleanupTasks.isEmpty()) { - systemSecurityContext.runAsSystem(this::executeAutoCleanup); + asSystem(this::executeAutoCleanup); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/event/JpaEventEntityManager.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/event/JpaEventEntityManager.java index bdd11273a..e23be40dd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/event/JpaEventEntityManager.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/event/JpaEventEntityManager.java @@ -9,11 +9,12 @@ */ package org.eclipse.hawkbit.repository.jpa.event; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; + import jakarta.persistence.EntityManager; import org.eclipse.hawkbit.repository.event.remote.EventEntityManager; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.transaction.annotation.Transactional; /** @@ -22,22 +23,19 @@ import org.springframework.transaction.annotation.Transactional; @Transactional(readOnly = true) public class JpaEventEntityManager implements EventEntityManager { - private final TenantAware tenantAware; private final EntityManager entityManager; /** * Constructor. * - * @param tenantAware the tenant aware * @param entityManager the entity manager */ - public JpaEventEntityManager(final TenantAware tenantAware, final EntityManager entityManager) { - this.tenantAware = tenantAware; + public JpaEventEntityManager(final EntityManager entityManager) { this.entityManager = entityManager; } @Override public E findEntity(final String tenant, final Long id, final Class entityType) { - return tenantAware.runAsTenant(tenant, () -> entityManager.find(entityType, id)); + return asSystemAsTenant(tenant, () -> entityManager.find(entityType, id)); } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/AbstractDsAssignmentStrategy.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/AbstractDsAssignmentStrategy.java index b7c1e2e28..08fd91c78 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/AbstractDsAssignmentStrategy.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/AbstractDsAssignmentStrategy.java @@ -21,6 +21,7 @@ import java.util.function.Consumer; import jakarta.persistence.criteria.JoinType; import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryProperties; @@ -87,7 +88,7 @@ public abstract class AbstractDsAssignmentStrategy { } public JpaAction createTargetAction( - final String initiatedBy, final TargetWithActionType targetWithActionType, + final TargetWithActionType targetWithActionType, final List targets, final JpaDistributionSet set) { final Optional optTarget = targets.stream() .filter(t -> t.getControllerId().equals(targetWithActionType.getControllerId())).findFirst(); @@ -108,7 +109,7 @@ public abstract class AbstractDsAssignmentStrategy { actionForTarget.setMaintenanceWindowSchedule(targetWithActionType.getMaintenanceSchedule()); actionForTarget.setMaintenanceWindowDuration(targetWithActionType.getMaintenanceWindowDuration()); actionForTarget.setMaintenanceWindowTimeZone(targetWithActionType.getMaintenanceWindowTimeZone()); - actionForTarget.setInitiatedBy(initiatedBy); + actionForTarget.setInitiatedBy(AccessContext.actor()); return actionForTarget; }).orElseGet(() -> { log.warn("Cannot find target for targetWithActionType '{}'.", targetWithActionType.getControllerId()); @@ -234,10 +235,8 @@ public abstract class AbstractDsAssignmentStrategy { * * @param distributionSet to set * @param targetIds to change - * @param currentUser for auditing */ - abstract void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet distributionSet, - final List> targetIds, final String currentUser); + abstract void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet distributionSet, final List> targetIds); /** * Cancels actions that can be canceled (i.e. @@ -265,8 +264,7 @@ public abstract class AbstractDsAssignmentStrategy { final RolloutGroup rolloutGroup = action.getRolloutGroup(); if (rolloutGroup != null) { final Rollout rollout = rolloutGroup.getRollout(); - return String.format("Initiated by Rollout Group '%s' [Rollout %s:%s]", rolloutGroup.getName(), - rollout.getName(), rollout.getId()); + return String.format("Initiated by Rollout Group '%s' [Rollout %s:%s]", rolloutGroup.getName(), rollout.getName(), rollout.getId()); } return String.format("Assignment initiated by user '%s'", action.getInitiatedBy()); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaArtifactManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaArtifactManagement.java index cdbaaf688..fe8d43bc3 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaArtifactManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaArtifactManagement.java @@ -28,6 +28,7 @@ import org.eclipse.hawkbit.artifact.exception.HashNotMatchException; import org.eclipse.hawkbit.artifact.model.ArtifactHashes; import org.eclipse.hawkbit.artifact.model.ArtifactStream; import org.eclipse.hawkbit.artifact.model.StoredArtifactInfo; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; @@ -49,7 +50,6 @@ import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.ArtifactUpload; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.retry.annotation.Backoff; @@ -74,7 +74,6 @@ public class JpaArtifactManagement implements ArtifactManagement { private final SoftwareModuleRepository softwareModuleRepository; private final EntityManager entityManager; private final PlatformTransactionManager txManager; - private final TenantAware tenantAware; private final QuotaManagement quotaManagement; protected JpaArtifactManagement( @@ -83,15 +82,13 @@ public class JpaArtifactManagement implements ArtifactManagement { final SoftwareModuleRepository softwareModuleRepository, final EntityManager entityManager, final PlatformTransactionManager txManager, - final QuotaManagement quotaManagement, - final TenantAware tenantAware) { + final QuotaManagement quotaManagement) { this.artifactRepository = artifactRepository; this.artifactStorage = artifactStorage.orElse(null); this.softwareModuleRepository = softwareModuleRepository; this.entityManager = entityManager; this.txManager = txManager; this.quotaManagement = quotaManagement; - this.tenantAware = tenantAware; } @Override @@ -135,7 +132,7 @@ public class JpaArtifactManagement implements ArtifactManagement { try { return storeArtifactMetadata(softwareModule, filename, artifact.getHashes(), artifact.getSize(), existing); } catch (final Exception e) { - artifactStorage.deleteBySha1(tenantAware.getCurrentTenant(), artifact.getHashes().sha1()); + artifactStorage.deleteBySha1(AccessContext.tenant(), artifact.getHashes().sha1()); throw e; } } @@ -147,7 +144,7 @@ public class JpaArtifactManagement implements ArtifactManagement { throw new UnsupportedOperationException(); } - final String tenant = tenantAware.getCurrentTenant(); + final String tenant = AccessContext.tenant(); // check access to the software module and if artifact belongs to it for (final Artifact artifact : softwareModuleRepository.getById(softwareModuleId).getArtifacts()) { if (artifact.getSha1Hash().equals(sha1Hash)) { @@ -203,13 +200,13 @@ public class JpaArtifactManagement implements ArtifactManagement { void clearArtifactBinary(final String sha1Hash) { DeploymentHelper.runInNewTransaction(txManager, "clearArtifactBinary", status -> { // countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse will skip ACM checks and will return total count as it should be - if (artifactRepository.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(sha1Hash, tenantAware.getCurrentTenant()) <= 0) { + if (artifactRepository.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(sha1Hash, AccessContext.tenant()) <= 0) { // removes the real artifact ONLY AFTER the delete of artifact or software module // in local history has passed successfully (caller has permission and no errors) afterCommit(() -> { try { log.debug("deleting artifact from repository {}", sha1Hash); - artifactStorage.deleteBySha1(tenantAware.getCurrentTenant(), sha1Hash); + artifactStorage.deleteBySha1(AccessContext.tenant(), sha1Hash); } catch (final ArtifactStoreException e) { throw new ArtifactDeleteFailedException(e); } @@ -224,7 +221,7 @@ public class JpaArtifactManagement implements ArtifactManagement { try (final InputStream wrappedStream = wrapInQuotaStream( isSmEncrypted ? ArtifactEncryptionService.getInstance().encryptArtifact(artifactUpload.moduleId(), stream) : stream)) { return artifactStorage.store( - tenantAware.getCurrentTenant(), + AccessContext.tenant(), wrappedStream, artifactUpload.filename(), artifactUpload.contentType(), artifactUpload.hash()); } catch (final ArtifactStoreException | IOException e) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaConfirmationManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaConfirmationManagement.java index f911af3e7..281896032 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaConfirmationManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaConfirmationManagement.java @@ -22,7 +22,6 @@ import jakarta.persistence.EntityManager; import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.ConfirmationManagement; import org.eclipse.hawkbit.repository.QuotaManagement; -import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.exception.AutoConfirmationAlreadyActiveException; import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java index 958523db4..955c9f97a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java @@ -9,6 +9,9 @@ */ package org.eclipse.hawkbit.repository.jpa.management; +import static org.eclipse.hawkbit.context.AccessContext.asActor; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; import static org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor.afterCommit; import static org.eclipse.hawkbit.repository.model.Action.Status.DOWNLOADED; import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED; @@ -46,6 +49,7 @@ import jakarta.validation.constraints.NotEmpty; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ql.jpa.QLSupport; import org.eclipse.hawkbit.repository.ConfirmationManagement; import org.eclipse.hawkbit.repository.ControllerManagement; @@ -55,9 +59,8 @@ import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryProperties; -import org.eclipse.hawkbit.repository.SecurityTokenGeneratorHolder; +import org.eclipse.hawkbit.repository.SecurityTokenGenerator; import org.eclipse.hawkbit.repository.SoftwareModuleManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent; @@ -68,6 +71,7 @@ import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException; import org.eclipse.hawkbit.repository.exception.SoftwareModuleNotAssignedToTargetException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.jpa.Jpa; import org.eclipse.hawkbit.repository.jpa.acm.AccessController; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; @@ -101,13 +105,11 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.qfields.TargetFields; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.configuration.ControllerPollProperties; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; import org.eclipse.hawkbit.tenancy.configuration.PollingTime; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; -import org.eclipse.hawkbit.util.IpUtil; +import org.eclipse.hawkbit.utils.IpUtil; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.data.domain.Page; @@ -137,8 +139,6 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont private static final Pattern PATTERN = Pattern.compile("[a-zA-Z0-9_\\-!@#$%^&*()+=\\[\\]{}|;:'\",.<>/\\\\?\\s]*"); - private final BlockingDeque queue; - // TODO - make it final private TargetRepository targetRepository; private final TargetTypeRepository targetTypeRepository; @@ -147,14 +147,13 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont private final SoftwareModuleRepository softwareModuleRepository; private final SoftwareModuleManagement softwareModuleManagement; private final DistributionSetManagement distributionSetManagement; - private final TenantConfigurationManagement tenantConfigurationManagement; private final ControllerPollProperties controllerPollProperties; - private final Duration minPollingTime; - private final Duration maxPollingTime; private final PlatformTransactionManager txManager; private final EntityManager entityManager; - private final SystemSecurityContext systemSecurityContext; - private final TenantAware tenantAware; + + private final Duration minPollingTime; + private final Duration maxPollingTime; + private final BlockingDeque queue; @SuppressWarnings("squid:S00107") protected JpaControllerManagement( @@ -165,9 +164,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont final SoftwareModuleRepository softwareModuleRepository, final SoftwareModuleManagement softwareModuleManagement, final DistributionSetManagement distributionSetManagement, - final TenantConfigurationManagement tenantConfigurationManagement, final ControllerPollProperties controllerPollProperties, + final ControllerPollProperties controllerPollProperties, final PlatformTransactionManager txManager, final EntityManager entityManager, - final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final ScheduledExecutorService executorService) { super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties); @@ -178,19 +176,16 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont this.softwareModuleRepository = softwareModuleRepository; this.softwareModuleManagement = softwareModuleManagement; this.distributionSetManagement = distributionSetManagement; - this.tenantConfigurationManagement = tenantConfigurationManagement; this.controllerPollProperties = controllerPollProperties; + this.txManager = txManager; + this.entityManager = entityManager; + minPollingTime = controllerPollProperties.getMinPollingTime() == null ? Duration.of(0, ChronoUnit.SECONDS) : DurationHelper.fromString(controllerPollProperties.getMinPollingTime()); maxPollingTime = controllerPollProperties.getMaxPollingTime() == null ? Duration.of(100, ChronoUnit.YEARS) : DurationHelper.fromString(controllerPollProperties.getMaxPollingTime()); - this.txManager = txManager; - this.entityManager = entityManager; - this.systemSecurityContext = systemSecurityContext; - this.tenantAware = tenantAware; - if (!repositoryProperties.isEagerPollPersistence()) { executorService.scheduleWithFixedDelay(this::flushUpdateQueue, repositoryProperties.getPollPersistenceFlushTime(), @@ -277,7 +272,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont @Override public Map> findTargetVisibleMetaDataBySoftwareModuleId(final Collection moduleId) { - return systemSecurityContext.runAsSystem(() -> softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(moduleId)); + return asSystem(() -> softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(moduleId)); } @Override @@ -383,9 +378,11 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont @Override public String getPollingTime(final Target target) { - return systemSecurityContext.runAsSystem(() -> { + // as system so to be able to read tenant configuration (READ_TENANT_CONFIGURATION) + return asSystem(() -> { final PollingTime pollingTime = new PollingTime( - tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.POLLING_TIME, String.class).getValue()); + TenantConfigHelper.getTenantConfigurationManagement() + .getConfigurationValue(TenantConfigurationKey.POLLING_TIME, String.class).getValue()); if (!ObjectUtils.isEmpty(pollingTime.getOverrides()) && target instanceof JpaTarget jpaTarget) { for (final PollingTime.Override override : pollingTime.getOverrides()) { try { @@ -409,9 +406,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont return pollingTime; } else { // the count to be used for reducing polling interval -> the configured value of {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT} - final int maintenanceWindowPollCount = systemSecurityContext.runAsSystem( - () -> tenantConfigurationManagement.getConfigurationValue( - TenantConfigurationKey.MAINTENANCE_WINDOW_POLL_COUNT, Integer.class).getValue()); + final int maintenanceWindowPollCount = TenantConfigHelper.getAsSystem( + TenantConfigurationKey.MAINTENANCE_WINDOW_POLL_COUNT, Integer.class); return new EventTimer(pollingTime, controllerPollProperties.getMinPollingTime(), ChronoUnit.SECONDS) .timeToNextEvent(maintenanceWindowPollCount, action.getMaintenanceWindowStartTime().orElse(null)); } @@ -524,7 +520,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont jpaAction.setStatus(Status.CANCELING); // document that the status has been retrieved actionStatusRepository.save( - new JpaActionStatus(jpaAction, Status.CANCELING, System.currentTimeMillis(), "manual cancelation requested")); + new JpaActionStatus(jpaAction, Status.CANCELING, java.lang.System.currentTimeMillis(), "manual cancelation requested")); final Action saveAction = actionRepository.save(jpaAction); cancelAssignDistributionSetEvent(jpaAction); @@ -572,9 +568,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont @Override public boolean updateOfflineAssignedVersion(@NotEmpty final String controllerId, final String distributionName, final String version) { List distributionSetAssignmentResults = - systemSecurityContext.runAsSystem(() -> deploymentManagement.offlineAssignedDistributionSets( - controllerId, - List.of(Map.entry(controllerId, distributionSetManagement.findByNameAndVersion(distributionName, version).getId())))); + asSystem(() -> asActor(controllerId, () -> deploymentManagement.offlineAssignedDistributionSets( + List.of(Map.entry(controllerId, distributionSetManagement.findByNameAndVersion(distributionName, version).getId()))))); return distributionSetAssignmentResults.stream() .findFirst() @@ -656,9 +651,9 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont jpaTarget.setControllerId(controllerId); jpaTarget.setDescription("Plug and Play target: " + controllerId); jpaTarget.setName((StringUtils.hasText(name) ? name : controllerId)); - jpaTarget.setSecurityToken(SecurityTokenGeneratorHolder.getInstance().generateToken()); + jpaTarget.setSecurityToken(SecurityTokenGenerator.generateToken()); jpaTarget.setUpdateStatus(TargetUpdateStatus.REGISTERED); - jpaTarget.setLastTargetQuery(System.currentTimeMillis()); + jpaTarget.setLastTargetQuery(java.lang.System.currentTimeMillis()); jpaTarget.setAddress(Optional.ofNullable(address).map(URI::toString).orElse(null)); if (StringUtils.hasText(type)) { @@ -701,8 +696,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont try { events.stream().collect(Collectors.groupingBy(TargetPoll::getTenant)).forEach((tenant, polls) -> { final TransactionCallback createTransaction = status -> updateLastTargetQueries(tenant, polls); - tenantAware.runAsTenant(tenant, - () -> DeploymentHelper.runInNewTransaction(txManager, "flushUpdateQueue", createTransaction)); + asSystemAsTenant( + tenant, () -> DeploymentHelper.runInNewTransaction(txManager, "flushUpdateQueue", createTransaction)); }); } catch (final RuntimeException ex) { log.error("Failed to persist UpdateQueue content.", ex); @@ -720,7 +715,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont Constants.MAX_ENTRIES_IN_STATEMENT); pollChunks.forEach(chunk -> { - setLastTargetQuery(tenant, System.currentTimeMillis(), chunk); + setLastTargetQuery(tenant, java.lang.System.currentTimeMillis(), chunk); chunk.forEach(controllerId -> afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher() .publishEvent(new TargetPollEvent(controllerId, tenant)))); }); @@ -781,7 +776,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont if (isStatusUnknown(toUpdate.getUpdateStatus())) { toUpdate.setUpdateStatus(TargetUpdateStatus.REGISTERED); } - toUpdate.setLastTargetQuery(System.currentTimeMillis()); + toUpdate.setLastTargetQuery(java.lang.System.currentTimeMillis()); afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new TargetPollEvent(toUpdate))); return targetRepository.save(toUpdate); } @@ -827,7 +822,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont target.setRequestControllerAttributes(true); EventPublisherHolder.getInstance().getEventPublisher() - .publishEvent(new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(), + .publishEvent(new TargetAttributesRequestedEvent(AccessContext.tenant(), target.getId(), JpaTarget.class, target.getControllerId(), target.getAddress() != null ? target.getAddress() : null)); } @@ -908,7 +903,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont // case controller retrieves a action multiple times. if (resultList.isEmpty() || (Status.RETRIEVED != resultList.get(0)[1])) { // document that the status has been retrieved - actionStatusRepository.save(new JpaActionStatus(action, Status.RETRIEVED, System.currentTimeMillis(), message)); + actionStatusRepository.save(new JpaActionStatus(action, Status.RETRIEVED, java.lang.System.currentTimeMillis(), message)); // don't change the action status itself in case the action is in // canceling state otherwise diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java index 3129afb6e..65d66c001 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java @@ -9,9 +9,9 @@ */ package org.eclipse.hawkbit.repository.jpa.management; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED; -import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -38,12 +38,12 @@ import jakarta.persistence.criteria.Root; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ql.jpa.QLSupport; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryProperties; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; @@ -53,6 +53,7 @@ import org.eclipse.hawkbit.repository.exception.IncompatibleTargetTypeException; import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.jpa.Jpa; import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper; import org.eclipse.hawkbit.repository.jpa.acm.AccessController; @@ -86,14 +87,10 @@ import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetWithActionType; import org.eclipse.hawkbit.repository.qfields.ActionFields; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.dao.ConcurrencyFailureException; -import org.springframework.data.domain.AuditorAware; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; @@ -132,34 +129,30 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl "DELETE FROM sp_action " + "WHERE id IN (SELECT id FROM sp_action " + "WHERE tenant=" + Jpa.nativeQueryParamPrefix() + "tenant" + " AND status IN (%s)" + " AND last_modified_at<" + Jpa.nativeQueryParamPrefix() + "last_modified_at LIMIT " + ACTION_PAGE_LIMIT + ")"); } - private final EntityManager entityManager; private final JpaDistributionSetManagement distributionSetManagement; private final TargetRepository targetRepository; - private final AuditorAware auditorProvider; + private final EntityManager entityManager; private final PlatformTransactionManager txManager; + private final Database database; + + private final RetryTemplate retryTemplate; private final OnlineDsAssignmentStrategy onlineDsAssignmentStrategy; private final OfflineDsAssignmentStrategy offlineDsAssignmentStrategy; - private final TenantConfigurationManagement tenantConfigurationManagement; - private final SystemSecurityContext systemSecurityContext; - private final TenantAware tenantAware; - private final AuditorAware auditorAware; - private final Database database; - private final RetryTemplate retryTemplate; @SuppressWarnings("java:S107") - protected JpaDeploymentManagement(final EntityManager entityManager, final ActionRepository actionRepository, + protected JpaDeploymentManagement( + final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository, + final QuotaManagement quotaManagement, final RepositoryProperties repositoryProperties, final JpaDistributionSetManagement distributionSetManagement, final TargetRepository targetRepository, - final ActionStatusRepository actionStatusRepository, final AuditorAware auditorProvider, - final PlatformTransactionManager txManager, - final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement, - final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final AuditorAware auditorAware, - final JpaProperties jpaProperties, final RepositoryProperties repositoryProperties) { + final EntityManager entityManager, final PlatformTransactionManager txManager, final JpaProperties jpaProperties) { super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties); - this.entityManager = entityManager; this.distributionSetManagement = distributionSetManagement; this.targetRepository = targetRepository; - this.auditorProvider = auditorProvider; + this.entityManager = entityManager; this.txManager = txManager; + this.database = jpaProperties.getDatabase(); + + retryTemplate = createRetryTemplate(); final Consumer maxAssignmentsExceededHandler = maxAssignmentsExceededInfo -> handleMaxAssignmentsExceeded( maxAssignmentsExceededInfo.targetId, @@ -171,51 +164,26 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl offlineDsAssignmentStrategy = new OfflineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository, quotaManagement, this::isMultiAssignmentsEnabled, this::isConfirmationFlowEnabled, repositoryProperties, maxAssignmentsExceededHandler); - this.tenantConfigurationManagement = tenantConfigurationManagement; - this.systemSecurityContext = systemSecurityContext; - this.tenantAware = tenantAware; - this.auditorAware = auditorAware; - this.database = jpaProperties.getDatabase(); - this.retryTemplate = createRetryTemplate(); - } - - @Override - @Transactional(isolation = Isolation.READ_COMMITTED) - public List assignDistributionSets(final List deploymentRequests) { - return assignDistributionSets0(tenantAware.getCurrentUsername(), deploymentRequests, null); } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public List assignDistributionSets( - final String initiatedBy, final List deploymentRequests, final String actionMessage) { - return assignDistributionSets0(initiatedBy, deploymentRequests, actionMessage); - } - - private List assignDistributionSets0( - final String initiatedBy, final List deploymentRequests, final String actionMessage) { - WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(deploymentRequests); - return assignDistributionSets(initiatedBy, deploymentRequests, actionMessage, onlineDsAssignmentStrategy); + final List deploymentRequests, final String actionMessage) { + WeightValidationHelper.validate(deploymentRequests); + return assignDistributionSets(deploymentRequests, actionMessage, onlineDsAssignmentStrategy); } @Override - public List offlineAssignedDistributionSets( - final String initiatedBy, final Collection> assignments) { + @Transactional(isolation = Isolation.READ_COMMITTED) + public List offlineAssignedDistributionSets(final Collection> assignments) { final Collection> distinctAssignments = assignments.stream().distinct().toList(); enforceMaxAssignmentsPerRequest(distinctAssignments.size()); final List deploymentRequests = distinctAssignments.stream() .map(entry -> DeploymentRequest.builder(entry.getKey(), entry.getValue()).build()).toList(); - return assignDistributionSets( - auditorAware.getCurrentAuditor().orElse(tenantAware.getCurrentUsername()), deploymentRequests, null, - offlineDsAssignmentStrategy); - } - - @Override - @Transactional(isolation = Isolation.READ_COMMITTED) - public List offlineAssignedDistributionSets(final Collection> assignments) { - return offlineAssignedDistributionSets(tenantAware.getCurrentUsername(), assignments); + return assignDistributionSets(deploymentRequests, null, offlineDsAssignmentStrategy); } @Override @@ -242,7 +210,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl action.setStatus(Status.CANCELING); // document that the status has been retrieved - actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(), + actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, java.lang.System.currentTimeMillis(), RepositoryConstants.SERVER_MESSAGE_PREFIX + "manual cancelation requested")); final Action saveAction = actionRepository.save(action); @@ -384,7 +352,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl log.warn("action ({}) was still active and has been force quite.", action); // document that the status has been retrieved - actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELED, System.currentTimeMillis(), + actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELED, java.lang.System.currentTimeMillis(), RepositoryConstants.SERVER_MESSAGE_PREFIX + "A force quit has been performed.")); DeploymentHelper.successCancellation(action, actionRepository, targetRepository); @@ -533,7 +501,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl String.format(getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(database), Jpa.formatNativeQueryInClause("status", statusList))); - deleteQuery.setParameter("tenant", tenantAware.getCurrentTenant().toUpperCase()); + deleteQuery.setParameter("tenant", AccessContext.tenant().toUpperCase()); Jpa.setNativeQueryInParameter(deleteQuery, "status", statusList); deleteQuery.setParameter("last_modified_at", lastModified); @@ -603,8 +571,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl } } - ; - /** * Deletes the first n target actions of a target * @@ -628,11 +594,11 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl } private int getActionsPurgePercentage() { - return getConfigValue(TenantConfigurationKey.ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE, Integer.class); + return TenantConfigHelper.getAsSystem(TenantConfigurationKey.ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE, Integer.class); } protected boolean isActionsAutocloseEnabled() { - return getConfigValue(REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, Boolean.class); + return TenantConfigHelper.getAsSystem(REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, Boolean.class); } private static Map> convertRequest(final Collection deploymentRequests) { @@ -667,21 +633,20 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl backOffPolicy.setBackOffPeriod(Constants.TX_RT_DELAY); template.setBackOffPolicy(backOffPolicy); - final SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(Constants.TX_RT_MAX, - Collections.singletonMap(ConcurrencyFailureException.class, true)); + final SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy( + Constants.TX_RT_MAX, Collections.singletonMap(ConcurrencyFailureException.class, true)); template.setRetryPolicy(retryPolicy); return template; } private List assignDistributionSets( - final String initiatedBy, final List deploymentRequests, final String actionMessage, - final AbstractDsAssignmentStrategy strategy) { + final List deploymentRequests, final String actionMessage, final AbstractDsAssignmentStrategy strategy) { final List validatedRequests = validateAndFilterRequestForAssignments(deploymentRequests); final Map> assignmentsByDsIds = convertRequest(validatedRequests); final List results = assignmentsByDsIds.entrySet().stream() - .map(entry -> assignDistributionSetToTargetsWithRetry(initiatedBy, entry.getKey(), entry.getValue(), actionMessage, strategy)) + .map(entry -> assignDistributionSetToTargetsWithRetry(entry.getKey(), entry.getValue(), actionMessage, strategy)) .toList(); strategy.sendDeploymentEvents(results); return results; @@ -774,10 +739,10 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl } private DistributionSetAssignmentResult assignDistributionSetToTargetsWithRetry( - final String initiatedBy, final Long dsId, final Collection targetsWithActionType, final String actionMessage, + final Long dsId, final Collection targetsWithActionType, final String actionMessage, final AbstractDsAssignmentStrategy assignmentStrategy) { return retryTemplate.execute(retryContext -> - assignDistributionSetToTargets(initiatedBy, dsId, targetsWithActionType, actionMessage, assignmentStrategy)); + assignDistributionSetToTargets(dsId, targetsWithActionType, actionMessage, assignmentStrategy)); } /** @@ -793,7 +758,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl * to {@link TargetUpdateStatus#IN_SYNC}
* D. does not send a {@link TargetAssignDistributionSetEvent}.
* - * @param initiatedBy the username of the user who initiated the assignment * @param dsId the ID of the distribution set to assign * @param targetsWithActionType a list of all targets and their action type * @param actionMessage an optional message to be written into the action status @@ -803,7 +767,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl * {@link DistributionSetType}. */ private DistributionSetAssignmentResult assignDistributionSetToTargets( - final String initiatedBy, final Long dsId, final Collection targetsWithActionType, final String actionMessage, + final Long dsId, final Collection targetsWithActionType, final String actionMessage, final AbstractDsAssignmentStrategy assignmentStrategy) { final JpaDistributionSet dsValidAndComplete = distributionSetManagement.getValidAndComplete(dsId); final JpaDistributionSet distributionSet; @@ -837,7 +801,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl .filter(target -> existingTargetIds.contains(target.getControllerId())).toList(); final List assignedActions = doAssignDistributionSetToTargets( - initiatedBy, existingTargetsWithActionType, actionMessage, assignmentStrategy, distributionSet, targetEntities); + existingTargetsWithActionType, actionMessage, assignmentStrategy, distributionSet, targetEntities); return buildAssignmentResult(distributionSet, assignedActions, existingTargetsWithActionType.size()); } @@ -849,7 +813,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl return new DistributionSetAssignmentResult(distributionSetEntity, alreadyAssignedCount, Collections.emptyList()); } - private List doAssignDistributionSetToTargets(final String initiatedBy, + private List doAssignDistributionSetToTargets( final Collection targetsWithActionType, final String actionMessage, final AbstractDsAssignmentStrategy assignmentStrategy, final JpaDistributionSet distributionSetEntity, final List targetEntities) { @@ -863,7 +827,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl targetEntitiesIdsChunks.forEach(this::cancelInactiveScheduledActionsForTargets); setAssignedDistributionSetAndTargetUpdateStatus(assignmentStrategy, distributionSetEntity, targetEntitiesIdsChunks); final Map assignedActions = - createActions(targetsWithActionType, targetEntities, distributionSetEntity, assignmentStrategy, initiatedBy); + createActions(targetsWithActionType, targetEntities, distributionSetEntity, assignmentStrategy); // create initial action status when action is created, so we remember // the initial running status because we will change the status // of the action itself and with this action status we have a nicer action history. @@ -888,7 +852,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl private void checkMaxAssignmentQuota(final String controllerId, final long requested) { final int quota = quotaManagement.getMaxActionsPerTarget(); try { - systemSecurityContext.runAsSystem(() -> QuotaHelper.assertAssignmentQuota( + asSystem(() -> QuotaHelper.assertAssignmentQuota( controllerId, requested, quota, Action.class, Target.class, actionRepository::countByTargetControllerId)); } catch (final AssignmentQuotaExceededException ex) { targetRepository.findByControllerId(controllerId).ifPresentOrElse( @@ -908,18 +872,18 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl } } - private void setAssignedDistributionSetAndTargetUpdateStatus(final AbstractDsAssignmentStrategy assignmentStrategy, + private void setAssignedDistributionSetAndTargetUpdateStatus( + final AbstractDsAssignmentStrategy assignmentStrategy, final JpaDistributionSet set, final List> targetIdsChunks) { - final String currentUser = auditorProvider.getCurrentAuditor().orElse(null); - assignmentStrategy.setAssignedDistributionSetAndTargetStatus(set, targetIdsChunks, currentUser); + assignmentStrategy.setAssignedDistributionSetAndTargetStatus(set, targetIdsChunks); } - private Map createActions(final Collection targetsWithActionType, - final List targets, final JpaDistributionSet set, final AbstractDsAssignmentStrategy assignmentStrategy, - final String initiatedBy) { + private Map createActions( + final Collection targetsWithActionType, + final List targets, final JpaDistributionSet set, final AbstractDsAssignmentStrategy assignmentStrategy) { final Map persistedActions = new LinkedHashMap<>(); for (final TargetWithActionType twt : targetsWithActionType) { - final JpaAction targetAction = assignmentStrategy.createTargetAction(initiatedBy, twt, targets, set); + final JpaAction targetAction = assignmentStrategy.createTargetAction(twt, targets, set); if (targetAction != null) { persistedActions.put(twt, actionRepository.save(targetAction)); } @@ -1054,15 +1018,11 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl } private boolean isMultiAssignmentsEnabled() { - return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).isMultiAssignmentsEnabled(); + return TenantConfigHelper.isMultiAssignmentsEnabled(); } private boolean isConfirmationFlowEnabled() { - return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).isConfirmationFlowEnabled(); - } - - private T getConfigValue(final String key, final Class valueType) { - return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue()); + return TenantConfigHelper.isUserConfirmationFlowEnabled(); } private void assertTargetReadAllowed(final Long targetId) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetInvalidationManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetInvalidationManagement.java index fe96653cc..8ec0be268 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetInvalidationManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetInvalidationManagement.java @@ -9,10 +9,13 @@ */ package org.eclipse.hawkbit.repository.jpa.management; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; + import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement; @@ -26,8 +29,6 @@ import org.eclipse.hawkbit.repository.model.ActionCancellationType; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.integration.support.locks.LockRegistry; import org.springframework.stereotype.Service; @@ -47,9 +48,7 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet private final TargetFilterQueryManagement targetFilterQueryManagement; private final PlatformTransactionManager txManager; private final RepositoryProperties repositoryProperties; - private final TenantAware tenantAware; private final LockRegistry lockRegistry; - private final SystemSecurityContext systemSecurityContext; @SuppressWarnings("java:S107") protected JpaDistributionSetInvalidationManagement( @@ -57,23 +56,20 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet final RolloutManagement rolloutManagement, final DeploymentManagement deploymentManagement, final TargetFilterQueryManagement targetFilterQueryManagement, final PlatformTransactionManager txManager, final RepositoryProperties repositoryProperties, - final TenantAware tenantAware, final LockRegistry lockRegistry, - final SystemSecurityContext systemSecurityContext) { + final LockRegistry lockRegistry) { this.distributionSetManagement = distributionSetManagement; this.rolloutManagement = rolloutManagement; this.deploymentManagement = deploymentManagement; this.targetFilterQueryManagement = targetFilterQueryManagement; this.txManager = txManager; this.repositoryProperties = repositoryProperties; - this.tenantAware = tenantAware; this.lockRegistry = lockRegistry; - this.systemSecurityContext = systemSecurityContext; } @Override public void invalidateDistributionSet(final DistributionSetInvalidation distributionSetInvalidation) { log.debug("Invalidate distribution sets {}", distributionSetInvalidation.getDistributionSetIds()); - final String tenant = tenantAware.getCurrentTenant(); + final String tenant = AccessContext.tenant(); if (shouldRolloutsBeCanceled(distributionSetInvalidation.getActionCancellationType())) { final String handlerId = JpaRolloutManagement.createRolloutLockKey(tenant); final Lock lock = lockRegistry.obtain(handlerId); @@ -131,7 +127,7 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet } // Do run as system to ensure all actions (even invisible) are canceled due to invalidation. - systemSecurityContext.runAsSystem(() -> { + asSystem(() -> { log.debug("Cancel auto assignments after ds invalidation. ID: {}", setId); targetFilterQueryManagement.cancelAutoAssignmentForDistributionSet(setId); }); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java index d5139f1bf..b9d9ee29c 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java @@ -34,12 +34,12 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetTagManagement; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.RepositoryProperties; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.DeletedException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; @@ -56,8 +56,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Statistic; import org.eclipse.hawkbit.repository.qfields.DistributionSetFields; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.data.domain.Page; @@ -83,7 +81,6 @@ public class JpaDistributionSetManagement private final DistributionSetTagRepository distributionSetTagRepository; private final TargetFilterQueryRepository targetFilterQueryRepository; private final QuotaManagement quotaManagement; - private final TenantConfigHelper tenantConfigHelper; private final RepositoryProperties repositoryProperties; @SuppressWarnings("java:S107") @@ -95,8 +92,6 @@ public class JpaDistributionSetManagement final DistributionSetTagRepository distributionSetTagRepository, final TargetFilterQueryRepository targetFilterQueryRepository, final QuotaManagement quotaManagement, - final SystemSecurityContext systemSecurityContext, - final TenantConfigurationManagement tenantConfigurationManagement, final RepositoryProperties repositoryProperties) { super(jpaRepository, entityManager); this.distributionSetTagManagement = distributionSetTagManagement; @@ -104,7 +99,6 @@ public class JpaDistributionSetManagement this.distributionSetTagRepository = distributionSetTagRepository; this.targetFilterQueryRepository = targetFilterQueryRepository; this.quotaManagement = quotaManagement; - this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); this.repositoryProperties = repositoryProperties; } @@ -209,7 +203,7 @@ public class JpaDistributionSetManagement return false; } - if (Boolean.FALSE.equals(tenantConfigHelper.getConfigValue(IMPLICIT_LOCK_ENABLED, Boolean.class))) { + if (Boolean.FALSE.equals(TenantConfigHelper.getAsSystem(IMPLICIT_LOCK_ENABLED, Boolean.class))) { // implicit lock disabled return false; } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetTagManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetTagManagement.java index 67b8e9eab..1396a44d3 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetTagManagement.java @@ -11,10 +11,10 @@ package org.eclipse.hawkbit.repository.jpa.management; import jakarta.persistence.EntityManager; -import org.eclipse.hawkbit.repository.qfields.DistributionSetTagFields; import org.eclipse.hawkbit.repository.DistributionSetTagManagement; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository; +import org.eclipse.hawkbit.repository.qfields.DistributionSetTagFields; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.stereotype.Service; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetTypeManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetTypeManagement.java index 5f98e3b21..fdf22c806 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetTypeManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetTypeManagement.java @@ -18,7 +18,6 @@ import java.util.Optional; import jakarta.persistence.EntityManager; -import org.eclipse.hawkbit.repository.qfields.DistributionSetTypeFields; import org.eclipse.hawkbit.repository.DistributionSetTypeManagement; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; @@ -36,6 +35,7 @@ import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpec import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.qfields.DistributionSetTypeFields; import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.cache.Cache; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutGroupManagement.java index 3d6d0c625..1dd1f3cf2 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutGroupManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutGroupManagement.java @@ -71,18 +71,16 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { private final ActionRepository actionRepository; private final TargetRepository targetRepository; private final EntityManager entityManager; - private final RolloutStatusCache rolloutStatusCache; @SuppressWarnings("java:S107") protected JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository, final RolloutRepository rolloutRepository, final ActionRepository actionRepository, - final TargetRepository targetRepository, final EntityManager entityManager, final RolloutStatusCache rolloutStatusCache) { + final TargetRepository targetRepository, final EntityManager entityManager) { this.rolloutGroupRepository = rolloutGroupRepository; this.rolloutRepository = rolloutRepository; this.actionRepository = actionRepository; this.targetRepository = targetRepository; this.entityManager = entityManager; - this.rolloutStatusCache = rolloutStatusCache; } @Override @@ -118,10 +116,10 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { final JpaRolloutGroup jpaRolloutGroup = (JpaRolloutGroup) rolloutGroupRepository.findById(rolloutGroupId).map(RolloutGroup.class::cast) .orElseThrow(() -> new EntityNotFoundException(RolloutGroup.class, rolloutGroupId)); - List rolloutStatusCountItems = rolloutStatusCache.getRolloutGroupStatus(rolloutGroupId); + List rolloutStatusCountItems = RolloutStatusCache.getRolloutGroupStatus(rolloutGroupId); if (CollectionUtils.isEmpty(rolloutStatusCountItems)) { rolloutStatusCountItems = actionRepository.getStatusCountByRolloutGroupId(rolloutGroupId); - rolloutStatusCache.putRolloutGroupStatus(rolloutGroupId, rolloutStatusCountItems); + RolloutStatusCache.putRolloutGroupStatus(rolloutGroupId, rolloutStatusCountItems); } final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus( @@ -225,7 +223,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { } private Map> getStatusCountItemForRolloutGroup(final List groupIds) { - final Map> fromCache = rolloutStatusCache + final Map> fromCache = RolloutStatusCache .getRolloutGroupStatus(groupIds); final List rolloutGroupIds = groupIds.stream().filter(id -> !fromCache.containsKey(id)).toList(); @@ -235,7 +233,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { final Map> fromDb = resultList.stream() .collect(Collectors.groupingBy(TotalTargetCountActionStatus::getId)); - rolloutStatusCache.putRolloutGroupStatus(fromDb); + RolloutStatusCache.putRolloutGroupStatus(fromDb); fromCache.putAll(fromDb); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutManagement.java index 1dd5f8157..391838cf4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutManagement.java @@ -29,9 +29,9 @@ import jakarta.validation.ValidationException; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.ContextAware; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.auth.SpRole; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ql.jpa.QLSupport; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.QuotaManagement; @@ -42,7 +42,6 @@ import org.eclipse.hawkbit.repository.RolloutHelper; import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.RolloutStatusCache; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; @@ -51,6 +50,7 @@ import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetExcepti import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.jpa.Jpa; import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; @@ -85,10 +85,7 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.qfields.RolloutFields; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.utils.ObjectCopyUtil; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.dao.ConcurrencyFailureException; @@ -129,17 +126,13 @@ public class JpaRolloutManagement implements RolloutManagement { private final RolloutGroupRepository rolloutGroupRepository; private final RolloutApprovalStrategy rolloutApprovalStrategy; private final StartNextGroupRolloutGroupSuccessAction startNextRolloutGroupAction; - private final RolloutStatusCache rolloutStatusCache; private final ActionRepository actionRepository; private final TargetManagement targetManagement; private final ActionStatusRepository actionStatusRepository; private final DistributionSetManagement distributionSetManagement; - private final TenantAware tenantAware; - private final TenantConfigurationManagement tenantConfigurationManagement; private final QuotaManagement quotaManagement; - private final SystemSecurityContext systemSecurityContext; - private final ContextAware contextAware; private final RepositoryProperties repositoryProperties; + private final OnlineDsAssignmentStrategy onlineDsAssignmentStrategy; protected JpaRolloutManagement( @@ -148,35 +141,26 @@ public class JpaRolloutManagement implements RolloutManagement { final RolloutGroupRepository rolloutGroupRepository, final RolloutApprovalStrategy rolloutApprovalStrategy, final StartNextGroupRolloutGroupSuccessAction startNextRolloutGroupAction, - final RolloutStatusCache rolloutStatusCache, final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository, final TargetRepository targetRepository, final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement, - final TenantAware tenantAware, - final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement, - final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final RepositoryProperties repositoryProperties) { this.entityManager = entityManager; this.rolloutRepository = rolloutRepository; this.rolloutGroupRepository = rolloutGroupRepository; this.rolloutApprovalStrategy = rolloutApprovalStrategy; this.startNextRolloutGroupAction = startNextRolloutGroupAction; - this.rolloutStatusCache = rolloutStatusCache; this.actionRepository = actionRepository; this.actionStatusRepository = actionStatusRepository; this.targetManagement = targetManagement; this.distributionSetManagement = distributionSetManagement; - this.tenantAware = tenantAware; - this.tenantConfigurationManagement = tenantConfigurationManagement; this.quotaManagement = quotaManagement; - this.systemSecurityContext = systemSecurityContext; - this.contextAware = contextAware; this.repositoryProperties = repositoryProperties; - this.onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository, + onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository, quotaManagement, this::isMultiAssignmentsEnabled, this::isConfirmationFlowEnabled, repositoryProperties, null); } @@ -223,20 +207,21 @@ public class JpaRolloutManagement implements RolloutManagement { } else { RolloutHelper.verifyRolloutGroupAmount(amountGroup, quotaManagement); } - - final JpaRollout rolloutRequest = new JpaRollout(); - ObjectCopyUtil.copy(rollout, rolloutRequest, false, UnaryOperator.identity()); - rolloutRequest.setDynamic(rollout.isDynamic()); // TODO - copy compares isDynamic == false and don't set it to false - remain null - // scheduled rollout, the creator shall have permissions to start rollout - if (rolloutRequest.getStartAt() != null && rolloutRequest.getStartAt() != Long.MAX_VALUE && // if scheduled rollout - !systemSecurityContext.hasPermission(SpPermission.HANDLE_ROLLOUT) && - !systemSecurityContext.hasPermission(SpRole.SYSTEM_ROLE)) { - throw new InsufficientPermissionException("You need permission to start rollouts to create a scheduled rollout"); - } - if (dynamicRolloutGroupTemplate != null && !rolloutRequest.isDynamic()) { + if (dynamicRolloutGroupTemplate != null && !rollout.isDynamic()) { throw new ValidationException("Dynamic group template is only allowed for dynamic rollouts"); } + // scheduled rollout, the creator shall have permissions to start rollout + if (rollout.getStartAt() != null && rollout.getStartAt() != Long.MAX_VALUE && // if scheduled rollout + !SpPermission.hasPermission(SpPermission.HANDLE_ROLLOUT) && + !SpPermission.hasPermission(SpRole.SYSTEM_ROLE)) { + throw new InsufficientPermissionException("You need permission to start rollouts to create a scheduled rollout"); + } + + final JpaRollout rolloutRequest = new JpaRollout(); + ObjectCopyUtil.copy(rollout, rolloutRequest, false, UnaryOperator.identity()); + // TODO - copy compares isDynamic == false and don't set it to false - remain null + rolloutRequest.setDynamic(rollout.isDynamic()); return createRolloutGroups( amountGroup, conditions, createRollout(rolloutRequest, amountGroup == 0), confirmationRequired, dynamicRolloutGroupTemplate); } @@ -318,11 +303,11 @@ public class JpaRolloutManagement implements RolloutManagement { final Rollout rollout = rolloutRepository.findById(rolloutId).map(Rollout.class::cast) .orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId)); - List rolloutStatusCountItems = rolloutStatusCache.getRolloutStatus(rolloutId); + List rolloutStatusCountItems = RolloutStatusCache.getRolloutStatus(rolloutId); if (CollectionUtils.isEmpty(rolloutStatusCountItems)) { rolloutStatusCountItems = actionRepository.getStatusCountByRolloutId(rolloutId); - rolloutStatusCache.putRolloutStatus(rolloutId, rolloutStatusCountItems); + RolloutStatusCache.putRolloutStatus(rolloutId, rolloutStatusCountItems); } final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus( @@ -520,8 +505,8 @@ public class JpaRolloutManagement implements RolloutManagement { private void softCancelActionsOfRollout(final Rollout rollout) { final List actions = actionRepository.findAll( ActionSpecifications - .byRolloutIdAndActiveAndStatusIsNot(rollout.getId(), - List.of(Action.Status.CANCELING)), // avoid cancelling state here, because it is count as still active + // avoid cancelling state here, because it is count as still active + .byRolloutIdAndActiveAndStatusIsNot(rollout.getId(), List.of(Action.Status.CANCELING)), Pageable.ofSize(maxActions)) .getContent(); log.info("Found {} active actions for rollout {}, performing soft cancel.", actions.size(), rollout.getId()); @@ -529,7 +514,7 @@ public class JpaRolloutManagement implements RolloutManagement { storeActionsAndStatuses(actions, Action.Status.CANCELING); // send cancellation messages to event publisher - onlineDsAssignmentStrategy.sendCancellationMessages(actions, tenantAware.getCurrentTenant()); + onlineDsAssignmentStrategy.sendCancellationMessages(actions, AccessContext.tenant()); } private void forceQuitActionsOfRollout(final Rollout rollout) { @@ -592,7 +577,7 @@ public class JpaRolloutManagement implements RolloutManagement { Jpa.setNativeQueryInParameter(updateQuery, "tid", targetIds); final int updated = updateQuery.executeUpdate(); log.info("{} of target assigned distribution values updated for tenant {}", - updated, tenantAware.getCurrentTenant()); + updated, AccessContext.tenant()); return updated; } @@ -607,7 +592,7 @@ public class JpaRolloutManagement implements RolloutManagement { Jpa.setNativeQueryInParameter(updateQuery, "tid", targetIds); final int updated = updateQuery.executeUpdate(); log.info("{} of target assigned distribution set to previously installed distribution value for tenant {}", - updated, tenantAware.getCurrentTenant()); + updated, AccessContext.tenant()); return updated; } @@ -693,7 +678,7 @@ public class JpaRolloutManagement implements RolloutManagement { } private JpaRollout createRollout(final JpaRollout rollout, final boolean pureDynamic) { - WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(rollout); + WeightValidationHelper.validate(rollout); rollout.setCreatedAt(System.currentTimeMillis()); @@ -725,7 +710,7 @@ public class JpaRolloutManagement implements RolloutManagement { if (rollout.getWeight().isEmpty()) { rollout.setWeight(repositoryProperties.getActionWeightIfAbsent()); } - contextAware.getCurrentContext().ifPresent(rollout::setAccessControlContext); + AccessContext.securityContext().ifPresent(rollout::setAccessControlContext); return rollout; } @@ -747,8 +732,7 @@ public class JpaRolloutManagement implements RolloutManagement { JpaRolloutGroup lastGroup = null; if (amountOfGroups == 0) { if (dynamicRolloutGroupTemplate == null) { - throw new ConstraintDeclarationException( - "At least one static rollout group must be defined for a static rollout"); + throw new ConstraintDeclarationException("At least one static rollout group must be defined for a static rollout"); } } else { // we can enforce the 'max targets per group' quota right here because @@ -890,7 +874,7 @@ public class JpaRolloutManagement implements RolloutManagement { return Collections.emptyMap(); } - final Map> fromCache = rolloutStatusCache.getRolloutStatus(rollouts); + final Map> fromCache = RolloutStatusCache.getRolloutStatus(rollouts); final List rolloutIds = rollouts.stream().filter(id -> !fromCache.containsKey(id)).toList(); if (!rolloutIds.isEmpty()) { @@ -898,7 +882,7 @@ public class JpaRolloutManagement implements RolloutManagement { final Map> fromDb = resultList.stream() .collect(Collectors.groupingBy(TotalTargetCountActionStatus::getId)); - rolloutStatusCache.putRolloutStatus(fromDb); + RolloutStatusCache.putRolloutStatus(fromDb); fromCache.putAll(fromDb); } @@ -1012,11 +996,11 @@ public class JpaRolloutManagement implements RolloutManagement { } private boolean isMultiAssignmentsEnabled() { - return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).isMultiAssignmentsEnabled(); + return TenantConfigHelper.isMultiAssignmentsEnabled(); } private boolean isConfirmationFlowEnabled() { - return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).isConfirmationFlowEnabled(); + return TenantConfigHelper.isUserConfirmationFlowEnabled(); } private record TargetCount(long total, String filter) {} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleManagement.java index 1e612130e..2b64bf8d4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleManagement.java @@ -26,7 +26,6 @@ import jakarta.persistence.EntityManager; import org.eclipse.hawkbit.artifact.encryption.ArtifactEncryptionService; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.QuotaManagement; -import org.eclipse.hawkbit.repository.qfields.SoftwareModuleFields; import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.IncompleteSoftwareModuleException; @@ -42,6 +41,7 @@ import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValue; +import org.eclipse.hawkbit.repository.qfields.SoftwareModuleFields; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.data.domain.Page; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleTypeManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleTypeManagement.java index be2675b53..f999fb11f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleTypeManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleTypeManagement.java @@ -14,12 +14,12 @@ import java.util.Optional; import jakarta.persistence.EntityManager; -import org.eclipse.hawkbit.repository.qfields.SoftwareModuleTypeFields; import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository; import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository; import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository; +import org.eclipse.hawkbit.repository.qfields.SoftwareModuleTypeFields; import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.cache.Cache; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSystemManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSystemManagement.java index 6707fd657..57e7e4939 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSystemManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSystemManagement.java @@ -9,6 +9,8 @@ */ package org.eclipse.hawkbit.repository.jpa.management; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; + import java.util.Set; import java.util.function.Consumer; @@ -16,9 +18,9 @@ import jakarta.persistence.EntityManager; import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.artifact.ArtifactStorage; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.SystemManagement; -import org.eclipse.hawkbit.repository.TenantStatsManagement; import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.jpa.CurrentTenantCacheKeyGenerator; @@ -43,10 +45,6 @@ import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; 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.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager.CacheEvictEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; @@ -57,7 +55,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.lang.Nullable; -import org.springframework.orm.jpa.vendor.Database; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; @@ -78,9 +75,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst private static final int MAX_TENANTS_QUERY = 1000; - private final String countArtifactQuery; - private final String countSoftwareModulesQuery; - private final TargetRepository targetRepository; private final TargetTypeRepository targetTypeRepository; private final TargetTagRepository targetTagRepository; @@ -93,10 +87,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst private final RolloutRepository rolloutRepository; private final TenantConfigurationRepository tenantConfigurationRepository; private final TenantMetaDataRepository tenantMetaDataRepository; - private final TenantStatsManagement systemStatsManagement; private final SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator; - private final SystemSecurityContext systemSecurityContext; - private final TenantAware tenantAware; private final PlatformTransactionManager txManager; private final EntityManager entityManager; private final RepositoryProperties repositoryProperties; @@ -112,8 +103,8 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst final DistributionSetRepository distributionSetRepository, final DistributionSetTypeRepository distributionSetTypeRepository, final DistributionSetTagRepository distributionSetTagRepository, final RolloutRepository rolloutRepository, final TenantConfigurationRepository tenantConfigurationRepository, final TenantMetaDataRepository tenantMetaDataRepository, - final TenantStatsManagement systemStatsManagement, final SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator, - final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final PlatformTransactionManager txManager, + final SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator, + final PlatformTransactionManager txManager, final EntityManager entityManager, final RepositoryProperties repositoryProperties, final JpaProperties properties) { this.targetRepository = targetRepository; @@ -128,17 +119,10 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst this.rolloutRepository = rolloutRepository; this.tenantConfigurationRepository = tenantConfigurationRepository; this.tenantMetaDataRepository = tenantMetaDataRepository; - this.systemStatsManagement = systemStatsManagement; this.currentTenantCacheKeyGenerator = currentTenantCacheKeyGenerator; - this.systemSecurityContext = systemSecurityContext; - this.tenantAware = tenantAware; this.txManager = txManager; this.entityManager = entityManager; this.repositoryProperties = repositoryProperties; - - final String isDeleted = isPostgreSql(properties) ? "false" : "0"; - countArtifactQuery = "SELECT COUNT(a.id) FROM sp_artifact a INNER JOIN sp_software_module sm ON a.software_module = sm.id WHERE sm.deleted = " + isDeleted; - countSoftwareModulesQuery = "select SUM(file_size) from sp_artifact a INNER JOIN sp_software_module sm ON a.software_module = sm.id WHERE sm.deleted = " + isDeleted; } @Autowired(required = false) // it's not required on dmf/ddi only instances @@ -152,34 +136,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst return currentTenantCacheKeyGenerator.currentTenantKeyGenerator(); } - @Override - @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, - backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public void deleteTenant(final String t) { - if (artifactStorage == null) { - throw new IllegalStateException("Artifact repository is not available. Can't delete tenant."); - } - - final String tenant = t.toUpperCase(); - tenantAware.runAsTenant(tenant, () -> DeploymentHelper.runInNewTransaction(txManager, "deleteTenant", status -> { - tenantMetaDataRepository.deleteByTenantIgnoreCase(tenant); - tenantConfigurationRepository.deleteByTenant(tenant); - targetRepository.deleteByTenant(tenant); - targetFilterQueryRepository.deleteByTenant(tenant); - rolloutRepository.deleteByTenant(tenant); - targetTypeRepository.deleteByTenant(tenant); - targetTagRepository.deleteByTenant(tenant); - distributionSetTagRepository.deleteByTenant(tenant); - distributionSetRepository.deleteByTenant(tenant); - distributionSetTypeRepository.deleteByTenant(tenant); - softwareModuleRepository.deleteByTenant(tenant); - artifactStorage.deleteByTenant(tenant); - softwareModuleTypeRepository.deleteByTenant(tenant); - return null; - })); - EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new CacheEvictEvent.Default(tenant, null, null)); - } - @Override public Page findTenants(final Pageable pageable) { return tenantMetaDataRepository.findTenants(pageable); @@ -190,51 +146,21 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst // Exception squid:S2229 - calling findTenants without transaction is intended in this case @SuppressWarnings("squid:S2229") public void forEachTenant(final Consumer consumer) { - forEachTenant0(consumer); - } - - private void forEachTenant0(final Consumer consumer) { Page tenants; Pageable query = PageRequest.of(0, MAX_TENANTS_QUERY); do { - tenants = findTenants(query); - tenants.forEach(tenant -> tenantAware.runAsTenant(tenant, () -> { + tenants = findTenants(query); // with IS_SYSTEM_CODE so we could find all tenants + tenants.forEach(tenant -> asSystemAsTenant(tenant, () -> { try { consumer.accept(tenant); } catch (final RuntimeException ex) { - log.debug("Exception on forEachTenant execution for tenant {}. Continue with next tenant.", - tenant, ex); - log.error("Exception on forEachTenant execution for tenant {} with error message [{}]. " - + "Continue with next tenant.", tenant, ex.getMessage()); + log.error("Exception on forEachTenant execution for tenant {} with error message [{}]. Continue with next tenant.", + tenant, ex.getMessage()); } - return null; })); } while ((query = tenants.nextPageable()) != Pageable.unpaged()); } - @Override - public SystemUsageReportWithTenants getSystemUsageStatisticsWithTenants() { - final SystemUsageReportWithTenants result = (SystemUsageReportWithTenants) getSystemUsageStatistics(); - usageStatsPerTenant(result); - return result; - } - - @Override - public SystemUsageReport getSystemUsageStatistics() { - final Number count = (Number) entityManager.createNativeQuery(countSoftwareModulesQuery).getSingleResult(); - - long sumOfArtifacts = 0; - if (count != null) { - sumOfArtifacts = count.longValue(); - } - - // we use native queries to punch through the tenant boundaries. This has to be used with care! - final long targets = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_target").getSingleResult()).longValue(); - final long artifacts = ((Number) entityManager.createNativeQuery(countArtifactQuery).getSingleResult()).longValue(); - final long actions = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_action").getSingleResult()).longValue(); - return new SystemUsageReportWithTenants(targets, artifacts, actions, sumOfArtifacts, tenantMetaDataRepository.count()); - } - @Override public TenantMetaData getTenantMetadata() { return getTenantMetadata0(true); @@ -265,23 +191,46 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst return tenantMetaDataRepository.save(data); } - private static boolean isPostgreSql(final JpaProperties properties) { - return Database.POSTGRESQL == properties.getDatabase(); + @Override + @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, + backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public void deleteTenant(final String t) { + if (artifactStorage == null) { + throw new IllegalStateException("Artifact repository is not available. Can't delete tenant."); + } + + final String tenant = t.toUpperCase(); + asSystemAsTenant(tenant, () -> DeploymentHelper.runInNewTransaction(txManager, "deleteTenant", status -> { + tenantMetaDataRepository.deleteByTenantIgnoreCase(tenant); + tenantConfigurationRepository.deleteByTenant(tenant); + targetRepository.deleteByTenant(tenant); + targetFilterQueryRepository.deleteByTenant(tenant); + rolloutRepository.deleteByTenant(tenant); + targetTypeRepository.deleteByTenant(tenant); + targetTagRepository.deleteByTenant(tenant); + distributionSetTagRepository.deleteByTenant(tenant); + distributionSetRepository.deleteByTenant(tenant); + distributionSetTypeRepository.deleteByTenant(tenant); + softwareModuleRepository.deleteByTenant(tenant); + artifactStorage.deleteByTenant(tenant); + softwareModuleTypeRepository.deleteByTenant(tenant); + return null; + })); + EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new CacheEvictEvent.Default(tenant, null, null)); } private TenantMetaData getTenantMetadata0(final boolean withDetails) { - final String tenant = tenantAware.getCurrentTenant(); + final String tenant = AccessContext.tenant(); if (tenant == null) { - throw new IllegalStateException("Tenant not set"); + throw new IllegalStateException("AccessContext not set"); } - final TenantMetaData metaData = - withDetails ? - tenantMetaDataRepository.findWitDetailsByTenantIgnoreCase(tenant) : - tenantMetaDataRepository.findByTenantIgnoreCase(tenant); + final TenantMetaData metaData = withDetails + ? tenantMetaDataRepository.findWitDetailsByTenantIgnoreCase(tenant) + : tenantMetaDataRepository.findByTenantIgnoreCase(tenant); if (metaData == null) { if (repositoryProperties.isImplicitTenantCreateAllowed()) { - log.info("Tenant {} doesn't exist create metadata", tenant, new Exception("Thread dump")); + log.info("AccessContext {} doesn't exist create metadata", tenant, new Exception("Thread dump")); return createTenantMetadata0(tenant); } else { throw new EntityNotFoundException(TenantMetaData.class, tenant); @@ -291,10 +240,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst } } - private void usageStatsPerTenant(final SystemUsageReportWithTenants report) { - forEachTenant0(tenant -> report.addTenantData(systemStatsManagement.getStatsOfTenant())); - } - private DistributionSetType createStandardSoftwareDataSetup() { final SoftwareModuleType app = softwareModuleTypeRepository.save( new JpaSoftwareModuleType( @@ -338,23 +283,20 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst } /** - * Creating the initial tenant meta-data in a new transaction. Due to the - * {@link org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager} is using the current tenant to - * set the necessary tenant discriminator to the query. This is not working - * if we don't have a current tenant set. Due to the - * {@link #createTenantMetadata(String)} is maybe called without having a - * current tenant we need to re-open a new transaction so the - * {@link org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager} is called again and set the + * Creating the initial tenant meta-data in a new transaction. Due to the tenant support it is using the current tenant to + * set the necessary tenant discriminator to the query. This is not working if we don't have a current tenant set. + * Due to the {@link #createTenantMetadata(String)} is maybe called without having a + * current tenant we need to re-open a new transaction so the tenant support is called again and set the * tenant for this transaction. * * @param tenant the tenant to be created * @return the initial created {@link TenantMetaData} */ private TenantMetaData createInitialTenantMetaData(final String tenant) { - return systemSecurityContext.runAsSystemAsTenant( - () -> DeploymentHelper.runInNewTransaction(txManager, "initial-tenant-creation", status -> { + return asSystemAsTenant( + tenant, () -> DeploymentHelper.runInNewTransaction(txManager, "initial-tenant-creation", status -> { final DistributionSetType defaultDsType = createStandardSoftwareDataSetup(); return tenantMetaDataRepository.save(new JpaTenantMetaData(defaultDsType, tenant)); - }), tenant); + })); } -} +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetFilterQueryManagement.java index 338bf3718..752e2ae2d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetFilterQueryManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetFilterQueryManagement.java @@ -18,19 +18,19 @@ import jakarta.persistence.EntityManager; import cz.jirutka.rsql.parser.RSQLParserException; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.ContextAware; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ql.jpa.QLSupport; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException; import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; @@ -44,10 +44,7 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.qfields.TargetFields; import org.eclipse.hawkbit.repository.qfields.TargetFilterQueryFields; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; -import org.springframework.data.domain.AuditorAware; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -66,34 +63,26 @@ import org.springframework.validation.annotation.Validated; @Service @ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "target-filter-management" }, matchIfMissing = true) class JpaTargetFilterQueryManagement - extends AbstractJpaRepositoryManagement + extends + AbstractJpaRepositoryManagement implements TargetFilterQueryManagement { private final TargetManagement targetManagement; private final DistributionSetManagement distributionSetManagement; private final QuotaManagement quotaManagement; - private final TenantConfigurationManagement tenantConfigurationManagement; private final RepositoryProperties repositoryProperties; - private final SystemSecurityContext systemSecurityContext; - private final ContextAware contextAware; - private final AuditorAware auditorAware; protected JpaTargetFilterQueryManagement( final TargetFilterQueryRepository targetFilterQueryRepository, final EntityManager entityManager, final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement, - final QuotaManagement quotaManagement, final TenantConfigurationManagement tenantConfigurationManagement, - final RepositoryProperties repositoryProperties, - final SystemSecurityContext systemSecurityContext, final ContextAware contextAware, final AuditorAware auditorAware) { + final QuotaManagement quotaManagement, + final RepositoryProperties repositoryProperties) { super(targetFilterQueryRepository, entityManager); this.targetManagement = targetManagement; this.distributionSetManagement = distributionSetManagement; this.quotaManagement = quotaManagement; - this.tenantConfigurationManagement = tenantConfigurationManagement; this.repositoryProperties = repositoryProperties; - this.systemSecurityContext = systemSecurityContext; - this.contextAware = contextAware; - this.auditorAware = auditorAware; } @Override @@ -161,7 +150,7 @@ class JpaTargetFilterQueryManagement targetFilterQuery.setAutoAssignInitiatedBy(null); targetFilterQuery.setConfirmationRequired(false); } else { - WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(update); + WeightValidationHelper.validate(update); assertMaxTargetsQuota(targetFilterQuery.getQuery(), targetFilterQuery.getName(), update.dsId()); DistributionSet distributionSet = distributionSetManagement.getValidAndComplete(update.dsId()); @@ -170,12 +159,13 @@ class JpaTargetFilterQueryManagement } targetFilterQuery.setAutoAssignDistributionSet(distributionSet); - contextAware.getCurrentContext().ifPresent(targetFilterQuery::setAccessControlContext); - targetFilterQuery.setAutoAssignInitiatedBy(auditorAware.getCurrentAuditor().orElse(targetFilterQuery.getCreatedBy())); + AccessContext.securityContext().ifPresent(targetFilterQuery::setAccessControlContext); + targetFilterQuery.setAutoAssignInitiatedBy(Optional.ofNullable(AccessContext.actor()).orElse(targetFilterQuery.getCreatedBy())); targetFilterQuery.setAutoAssignActionType(sanitizeAutoAssignActionType(update.actionType())); targetFilterQuery.setAutoAssignWeight(update.weight() == null ? repositoryProperties.getActionWeightIfAbsent() : update.weight()); - final boolean confirmationRequired = - update.confirmationRequired() == null ? isConfirmationFlowEnabled() : update.confirmationRequired(); + final boolean confirmationRequired = update.confirmationRequired() == null + ? TenantConfigHelper.isUserConfirmationFlowEnabled() + : update.confirmationRequired(); targetFilterQuery.setConfirmationRequired(confirmationRequired); } return jpaRepository.save(targetFilterQuery); @@ -200,10 +190,6 @@ class JpaTargetFilterQueryManagement return actionType; } - private boolean isConfirmationFlowEnabled() { - return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).isConfirmationFlowEnabled(); - } - private void assertMaxTargetsQuota(final String query, final String filterName, final long dsId) { QuotaHelper.assertAssignmentQuota(filterName, targetManagement.countByRsqlAndNonDsAndCompatibleAndUpdatable(dsId, query), @@ -230,7 +216,7 @@ class JpaTargetFilterQueryManagement // enforce the 'max targets per auto assign' quota right here even if the result of the filter query can vary over time Optional.ofNullable(create.getAutoAssignDistributionSet()).ifPresent(dsId -> { - WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(create); + WeightValidationHelper.validate(create); assertMaxTargetsQuota(query, create.getName(), dsId.getId()); }); }); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetTagManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetTagManagement.java index 1f868d62f..7ffbb1418 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetTagManagement.java @@ -11,10 +11,10 @@ package org.eclipse.hawkbit.repository.jpa.management; import jakarta.persistence.EntityManager; -import org.eclipse.hawkbit.repository.qfields.TargetTagFields; import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository; +import org.eclipse.hawkbit.repository.qfields.TargetTagFields; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetTypeManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetTypeManagement.java index 543c09195..971cf15e7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetTypeManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetTypeManagement.java @@ -16,7 +16,6 @@ import java.util.function.ToLongFunction; import jakarta.persistence.EntityManager; import org.eclipse.hawkbit.repository.QuotaManagement; -import org.eclipse.hawkbit.repository.qfields.TargetTypeFields; import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; @@ -31,6 +30,7 @@ import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.TargetType; +import org.eclipse.hawkbit.repository.qfields.TargetTypeFields; import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.cache.Cache; 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 58715edba..ef031f34d 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,7 +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.auth.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; @@ -30,12 +30,14 @@ import java.util.function.Function; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ql.jpa.QLSupport; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.exception.TenantConfigurationValidatorException; import org.eclipse.hawkbit.repository.exception.TenantConfigurationValueChangeNotAllowedException; -import org.eclipse.hawkbit.repository.helper.SystemSecurityContextHolder; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTenantConfiguration; @@ -45,7 +47,6 @@ 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.qfields.TargetFields; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; import org.eclipse.hawkbit.tenancy.configuration.PollingTime; @@ -54,6 +55,8 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; @@ -73,7 +76,7 @@ import org.springframework.validation.annotation.Validated; @Validated @Service @ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "tenant-configuration-management" }, matchIfMissing = true) -public class JpaTenantConfigurationManagement implements TenantConfigurationManagement { +public class JpaTenantConfigurationManagement implements TenantConfigurationManagement, ApplicationListener { private static final String CACHE_TENANT_CONFIGURATION_NAME = JpaTenantConfiguration.class.getSimpleName(); private static final ConfigurableConversionService CONVERSION_SERVICE = new DefaultConversionService(); @@ -91,6 +94,12 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana this.applicationContext = applicationContext; } + @Override + public void onApplicationEvent(final ContextRefreshedEvent event) { + // Sets the proxy / bean from the context in order to be used via proxy and onore things like @PreAuthorize and @Transactional + TenantConfigHelper.setTenantConfigurationManagement(applicationContext.getBean(JpaTenantConfigurationManagement.class)); + } + @Override @Transactional @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @@ -170,8 +179,7 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana private void checkAccess(final String keyName) { if (AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY.equalsIgnoreCase(keyName)) { - final SystemSecurityContext systemSecurityContext = SystemSecurityContextHolder.getInstance().getSystemSecurityContext(); - if (!SystemSecurityContext.isCurrentThreadSystemCode() && !systemSecurityContext.hasPermission(READ_GATEWAY_SECURITY_TOKEN)) { + if (!AccessContext.isCurrentThreadSystemCode() && !SpPermission.hasPermission(READ_GATEWAY_SECURITY_TOKEN)) { throw new InsufficientPermissionException( "Can't read gateway security token! " + READ_GATEWAY_SECURITY_TOKEN + " is required!"); } @@ -214,7 +222,8 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana .build())); } - private void validateConfigurationValue(final T value, final TenantConfigurationKey configurationKey, final Object convertedValue) { + private void validateConfigurationValue(final T value, final TenantConfigurationKey configurationKey, + final Object convertedValue) { configurationKey.validate(convertedValue, applicationContext); // additional validation for specific configuration keys if (POLLING_TIME.equals(configurationKey.getKeyName())) { @@ -254,7 +263,6 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana return convertedValue; } - @SuppressWarnings("unchecked") private TenantConfigurationValue getConfigurationValue0(final String keyName, final Class propertyType) { checkAccess(keyName); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantStatsManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantStatsManagement.java index cc94198ab..489d636ed 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantStatsManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantStatsManagement.java @@ -9,12 +9,12 @@ */ package org.eclipse.hawkbit.repository.jpa.management; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.TenantStatsManagement; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ArtifactRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.model.report.TenantUsage; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; @@ -32,21 +32,18 @@ public class JpaTenantStatsManagement implements TenantStatsManagement { private final TargetRepository targetRepository; private final ArtifactRepository artifactRepository; private final ActionRepository actionRepository; - private final TenantAware tenantAware; protected JpaTenantStatsManagement( - final TargetRepository targetRepository, final ArtifactRepository artifactRepository, final ActionRepository actionRepository, - final TenantAware tenantAware) { + final TargetRepository targetRepository, final ArtifactRepository artifactRepository, final ActionRepository actionRepository) { this.targetRepository = targetRepository; this.artifactRepository = artifactRepository; this.actionRepository = actionRepository; - this.tenantAware = tenantAware; } @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public TenantUsage getStatsOfTenant() { - final String tenant = tenantAware.getCurrentTenant(); + final String tenant = AccessContext.tenant(); final TenantUsage result = new TenantUsage(tenant); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/OfflineDsAssignmentStrategy.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/OfflineDsAssignmentStrategy.java index 704e3e9db..420242179 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/OfflineDsAssignmentStrategy.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/OfflineDsAssignmentStrategy.java @@ -15,6 +15,7 @@ import java.util.function.Consumer; import java.util.function.Function; import org.apache.commons.collections4.ListUtils; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryProperties; @@ -22,7 +23,6 @@ import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper; import org.eclipse.hawkbit.repository.jpa.acm.AccessController; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; -import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; import org.eclipse.hawkbit.repository.jpa.management.JpaDeploymentManagement.MaxAssignmentsExceededInfo; import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; @@ -54,9 +54,9 @@ class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy { } @Override - public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType, - final List targets, final JpaDistributionSet set) { - final JpaAction result = super.createTargetAction(initiatedBy, targetWithActionType, targets, set); + public JpaAction createTargetAction( + final TargetWithActionType targetWithActionType, final List targets, final JpaDistributionSet set) { + final JpaAction result = super.createTargetAction(targetWithActionType, targets, set); if (result != null) { result.setStatus(Status.FINISHED); result.setActive(Boolean.FALSE); @@ -94,8 +94,7 @@ class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy { } @Override - public void setAssignedDistributionSetAndTargetStatus( - final JpaDistributionSet set, final List> targetIds, final String currentUser) { + public void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet set, final List> targetIds) { final long now = System.currentTimeMillis(); targetIds.forEach(targetIdsChunk -> { if (targetRepository.count(AccessController.Operation.UPDATE, @@ -103,7 +102,7 @@ class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy { throw new InsufficientPermissionException("No update access to all targets!"); } targetRepository.setAssignedAndInstalledDistributionSetAndUpdateStatus( - TargetUpdateStatus.IN_SYNC, set, now, currentUser, targetIdsChunk); + TargetUpdateStatus.IN_SYNC, set, now, AccessContext.actor(), targetIdsChunk); // TODO AC - current problem with this approach is that the caller detach the targets and seems doesn't save them // targetRepository.saveAll( // targetRepository diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/OnlineDsAssignmentStrategy.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/OnlineDsAssignmentStrategy.java index b3060521c..f753f1d98 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/OnlineDsAssignmentStrategy.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/OnlineDsAssignmentStrategy.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.stream.Stream; import org.apache.commons.collections4.ListUtils; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.event.EventPublisherHolder; @@ -74,9 +75,9 @@ class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy { } @Override - public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType, + public JpaAction createTargetAction(final TargetWithActionType targetWithActionType, final List targets, final JpaDistributionSet set) { - final JpaAction result = super.createTargetAction(initiatedBy, targetWithActionType, targets, set); + final JpaAction result = super.createTargetAction(targetWithActionType, targets, set); if (result != null) { final boolean confirmationRequired = targetWithActionType.isConfirmationRequired() && result.getTarget().getAutoConfirmationStatus() == null; @@ -125,15 +126,15 @@ class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy { } @Override - public void setAssignedDistributionSetAndTargetStatus( - final JpaDistributionSet set, final List> targetIds, final String currentUser) { + public void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet set, final List> targetIds) { final long now = System.currentTimeMillis(); targetIds.forEach(targetIdsChunk -> { if (targetRepository.count(AccessController.Operation.UPDATE, targetRepository.byIdsSpec(targetIdsChunk)) != targetIdsChunk.size()) { throw new InsufficientPermissionException("No update access to all targets!"); } - targetRepository.setAssignedDistributionSetAndUpdateStatus(set, now, currentUser, TargetUpdateStatus.PENDING, targetIdsChunk); + targetRepository.setAssignedDistributionSetAndUpdateStatus( + set, now, AccessContext.actor(), TargetUpdateStatus.PENDING, targetIdsChunk); // TODO AC - current problem with this approach is that the caller detach the targets and seems doesn't save them // targetRepository.saveAll( // targetRepository diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetType.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetType.java index dad0423ad..9b83efc13 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetType.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSetType.java @@ -11,7 +11,6 @@ package org.eclipse.hawkbit.repository.jpa.model; import java.io.Serial; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -33,7 +32,6 @@ import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCre import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeUpdatedEvent; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; /** 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 75c718326..e2dd0eff7 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 @@ -48,11 +48,13 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.jpa.utils.MapAttributeConverter; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.PollStatus; @@ -60,9 +62,6 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.helper.SystemSecurityContextHolder; -import org.eclipse.hawkbit.repository.helper.TenantConfigurationManagementHolder; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.springframework.util.ObjectUtils; /** @@ -215,8 +214,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 (AccessContext.isCurrentThreadSystemCode() || SpPermission.hasPermission(SpPermission.READ_TARGET_SECURITY_TOKEN)) { return securityToken; } return null; @@ -232,7 +230,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw if (lastTargetQuery == null) { return null; } - return TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement() + return TenantConfigHelper.getTenantConfigurationManagement() .pollStatusResolver() .apply(this); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantMetaData.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantMetaData.java index 9ce98bd3e..d54dbbe10 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantMetaData.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTenantMetaData.java @@ -35,7 +35,7 @@ import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.eclipse.hawkbit.repository.model.TenantMetaData; /** - * Tenant entity with meta data that is configured globally for the entire + * AccessContext entity with meta data that is configured globally for the entire * tenant. This entity is not tenant aware to allow the system to access it * through the {@link EntityManager} even before the actual tenant exists. * diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/ActionRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/ActionRepository.java index ae96d5c2a..9a7576a29 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/ActionRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/ActionRepository.java @@ -9,7 +9,6 @@ */ package org.eclipse.hawkbit.repository.jpa.repository; -import java.util.Collection; import java.util.List; import java.util.Optional; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/DistributionSetTagRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/DistributionSetTagRepository.java index bde8dea98..b2389f860 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/DistributionSetTagRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/DistributionSetTagRepository.java @@ -10,12 +10,10 @@ package org.eclipse.hawkbit.repository.jpa.repository; import java.util.List; -import java.util.Optional; import jakarta.persistence.EntityManager; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.springframework.data.jpa.repository.Modifying; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/TargetTagRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/TargetTagRepository.java index 0380060a2..755e072a6 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/TargetTagRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/TargetTagRepository.java @@ -9,8 +9,6 @@ */ package org.eclipse.hawkbit.repository.jpa.repository; -import java.util.Optional; - import jakarta.persistence.EntityManager; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/PauseRolloutGroupAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/PauseRolloutGroupAction.java index 9d73e4c17..400f7fd88 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/PauseRolloutGroupAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/PauseRolloutGroupAction.java @@ -9,14 +9,14 @@ */ package org.eclipse.hawkbit.repository.jpa.rollout.condition; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; + import org.eclipse.hawkbit.repository.RolloutManagement; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; -import org.eclipse.hawkbit.security.SystemSecurityContext; /** * Error action evaluator which pauses the whole {@link Rollout} and sets the @@ -25,16 +25,12 @@ import org.eclipse.hawkbit.security.SystemSecurityContext; public class PauseRolloutGroupAction implements RolloutGroupActionEvaluator { private final RolloutManagement rolloutManagement; - private final RolloutGroupRepository rolloutGroupRepository; - private final SystemSecurityContext systemSecurityContext; - public PauseRolloutGroupAction(final RolloutManagement rolloutManagement, - final RolloutGroupRepository rolloutGroupRepository, final SystemSecurityContext systemSecurityContext) { + final RolloutGroupRepository rolloutGroupRepository) { this.rolloutManagement = rolloutManagement; this.rolloutGroupRepository = rolloutGroupRepository; - this.systemSecurityContext = systemSecurityContext; } @Override @@ -44,23 +40,19 @@ public class PauseRolloutGroupAction implements RolloutGroupActionEvaluator { - rolloutGroup.setStatus(RolloutGroupStatus.ERROR); - rolloutGroupRepository.save(rolloutGroup); - /* - Refresh latest rollout state in order to escape cases when - previous group have matched error condition and paused the rollout - and this one tries to pause the rollout too but throws an exception - and rollbacks rollout processing transaction - */ - final Rollout refreshedRollout = rolloutManagement.get(rollout.getId()); - if (Rollout.RolloutStatus.PAUSED != refreshedRollout.getStatus()) { - // if only the latest state is != paused then pause - rolloutManagement.pauseRollout(rollout.getId()); - } - }); + rolloutGroup.setStatus(RolloutGroupStatus.ERROR); + rolloutGroupRepository.save(rolloutGroup); + // Refresh latest rollout state in order to avoid cases when + // previous group have matched error condition and paused the rollout + // and this one tries to pause the rollout too but throws an exception + // and rollbacks rollout processing transaction + final Rollout refreshedRollout = rolloutManagement.get(rollout.getId()); + if (Rollout.RolloutStatus.PAUSED != refreshedRollout.getStatus()) { + // if only the latest state is != paused then pause + // execute as system if rollout creator has CREATE_ROLLOUT right but no HANDLE_ROLLOUT + asSystem(() -> rolloutManagement.pauseRollout(rollout.getId())); + } } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java index 18e9f01a0..9df7df4b9 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/condition/StartNextGroupRolloutGroupSuccessAction.java @@ -9,13 +9,14 @@ */ package org.eclipse.hawkbit.repository.jpa.rollout.condition; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; + import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; -import org.eclipse.hawkbit.security.SystemSecurityContext; /** * Success action which starts the next following {@link RolloutGroup}. @@ -25,14 +26,11 @@ public class StartNextGroupRolloutGroupSuccessAction implements RolloutGroupActi private final RolloutGroupRepository rolloutGroupRepository; private final DeploymentManagement deploymentManagement; - private final SystemSecurityContext systemSecurityContext; public StartNextGroupRolloutGroupSuccessAction( - final RolloutGroupRepository rolloutGroupRepository, final DeploymentManagement deploymentManagement, - final SystemSecurityContext systemSecurityContext) { + final RolloutGroupRepository rolloutGroupRepository, final DeploymentManagement deploymentManagement) { this.rolloutGroupRepository = rolloutGroupRepository; this.deploymentManagement = deploymentManagement; - this.systemSecurityContext = systemSecurityContext; } @Override @@ -40,11 +38,12 @@ public class StartNextGroupRolloutGroupSuccessAction implements RolloutGroupActi return RolloutGroup.RolloutGroupSuccessAction.NEXTGROUP; } - // Note - the exec could be called by JpaRolloutsExecutor and buy JpaRolloutsManagement#triggerNextGroup + // Note - the exec could be called by JpaRolloutsExecutor and by JpaRolloutsManagement#triggerNextGroup // this means it could be called by concurrently. @Override public void exec(final Rollout rollout, final RolloutGroup rolloutGroup) { - systemSecurityContext.runAsSystem(() -> { + // as system so to assume needed permissions. When called the permission to start next group are assumed anyway + asSystem(() -> { // retrieve all actions according to the parent group of the finished rolloutGroup, // so retrieve all child-group actions which need to be started. deploymentManagement.startScheduledActionsByRolloutGroupParent( diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignScheduler.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignScheduler.java index 994c5294d..e8c0ca1af 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignScheduler.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignScheduler.java @@ -9,6 +9,8 @@ */ package org.eclipse.hawkbit.repository.jpa.scheduler; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; + import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; @@ -17,7 +19,6 @@ import io.micrometer.core.instrument.MeterRegistry; import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.AutoAssignExecutor; import org.eclipse.hawkbit.repository.SystemManagement; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration; import org.springframework.integration.support.locks.LockRegistry; import org.springframework.scheduling.annotation.Scheduled; @@ -31,24 +32,14 @@ public class AutoAssignScheduler { private static final String PROP_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.scheduler.scheduler.fixedDelay:2000}"; private final SystemManagement systemManagement; - private final SystemSecurityContext systemSecurityContext; private final AutoAssignExecutor autoAssignExecutor; private final LockRegistry lockRegistry; private final Optional meterRegistry; - /** - * Instantiates a new AutoAssignScheduler - * - * @param systemManagement to find all tenants - * @param systemSecurityContext to run as system - * @param autoAssignExecutor to run a check as tenant - * @param lockRegistry to acquire a lock per tenant - */ - public AutoAssignScheduler(final SystemManagement systemManagement, - final SystemSecurityContext systemSecurityContext, final AutoAssignExecutor autoAssignExecutor, + public AutoAssignScheduler( + final SystemManagement systemManagement, final AutoAssignExecutor autoAssignExecutor, final LockRegistry lockRegistry, final Optional meterRegistry) { this.systemManagement = systemManagement; - this.systemSecurityContext = systemSecurityContext; this.autoAssignExecutor = autoAssignExecutor; this.lockRegistry = lockRegistry; this.meterRegistry = meterRegistry; @@ -56,13 +47,12 @@ public class AutoAssignScheduler { /** * Scheduler method called by the spring-async mechanism. Retrieves all tenants and runs for each - * tenant the auto assignments defined in the target filter queries {@link SystemSecurityContext}. + * tenant the auto assignments defined in the target filter queries {@link System}. */ @Scheduled(initialDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER) public void autoAssignScheduler() { - // run this code in system code privileged to have the necessary - // permission to query and create entities. - systemSecurityContext.runAsSystem(this::executeAutoAssign); + // run this code in system code privileged to have the necessary permission to query and create entities. + asSystem(this::executeAutoAssign); } @SuppressWarnings("squid:S3516") @@ -75,11 +65,11 @@ public class AutoAssignScheduler { return null; } - final long startNano = System.nanoTime(); + final long startNano = java.lang.System.nanoTime(); try { log.debug("Auto assign scheduled execution has acquired lock and started for each tenant."); systemManagement.forEachTenant(tenant -> { - final long startNanoT = System.nanoTime(); + final long startNanoT = java.lang.System.nanoTime(); autoAssignExecutor.checkAllTargets(); @@ -87,13 +77,13 @@ public class AutoAssignScheduler { .map(mReg -> mReg.timer( "hawkbit.scheduler.executor", DefaultTenantConfiguration.TENANT_TAG, tenant)) - .ifPresent(timer -> timer.record(System.nanoTime() - startNanoT, TimeUnit.NANOSECONDS)); + .ifPresent(timer -> timer.record(java.lang.System.nanoTime() - startNanoT, TimeUnit.NANOSECONDS)); }); } finally { lock.unlock(); meterRegistry .map(mReg -> mReg.timer("hawkbit.scheduler.executor.all")) - .ifPresent(timer -> timer.record(System.nanoTime() - startNano, TimeUnit.NANOSECONDS)); + .ifPresent(timer -> timer.record(java.lang.System.nanoTime() - startNano, TimeUnit.NANOSECONDS)); log.debug("Auto assign scheduled execution has released lock and finished."); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaAutoAssignExecutor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaAutoAssignExecutor.java index 132ca86ce..5d4460f28 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaAutoAssignExecutor.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaAutoAssignExecutor.java @@ -9,6 +9,9 @@ */ package org.eclipse.hawkbit.repository.jpa.scheduler; +import static org.eclipse.hawkbit.context.AccessContext.asActor; +import static org.eclipse.hawkbit.context.AccessContext.withSecurityContext; + import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -16,12 +19,11 @@ import java.util.function.Consumer; import jakarta.persistence.PersistenceException; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.ContextAware; import org.eclipse.hawkbit.exception.AbstractServerRtException; +import org.eclipse.hawkbit.repository.AutoAssignExecutor; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetManagement; -import org.eclipse.hawkbit.repository.AutoAssignExecutor; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.repository.model.Action; @@ -62,17 +64,15 @@ public class JpaAutoAssignExecutor implements AutoAssignExecutor { private final TargetManagement targetManagement; private final DeploymentManagement deploymentManagement; private final PlatformTransactionManager transactionManager; - private final ContextAware contextAware; public JpaAutoAssignExecutor( final TargetFilterQueryManagement targetFilterQueryManagement, final TargetManagement targetManagement, final DeploymentManagement deploymentManagement, - final PlatformTransactionManager transactionManager, final ContextAware contextAware) { + final PlatformTransactionManager transactionManager) { this.targetFilterQueryManagement = targetFilterQueryManagement; this.targetManagement = targetManagement; this.deploymentManagement = deploymentManagement; this.transactionManager = transactionManager; - this.contextAware = contextAware; } @Override @@ -84,7 +84,7 @@ public class JpaAutoAssignExecutor implements AutoAssignExecutor { } @Override - public void checkSingleTarget(String controllerId) { + public void checkSingleTarget(final String controllerId) { log.debug("Auto assign check call for device {} started", controllerId); forEachFilterWithAutoAssignDS(filter -> checkForDevice(controllerId, filter)); log.debug("Auto assign check call for device {} finished", controllerId); @@ -127,7 +127,7 @@ public class JpaAutoAssignExecutor implements AutoAssignExecutor { // run in the context the auto assignment is made in, i.e. if there is access control context it runs in it // otherwise in the tenant & user context built by createdBy - // Note: It must be called in a tenant context, i.e. contextAware.getCurrentTenant() returns the tenant + // Note: It must be called in a tenant context, i.e. Security.getCurrentTenant() returns the tenant private void forEachFilterWithAutoAssignDS(final Consumer consumer) { Slice filterQueries; Pageable query = PageRequest.of(0, PAGE_SIZE); @@ -137,14 +137,10 @@ public class JpaAutoAssignExecutor implements AutoAssignExecutor { filterQueries.forEach(filterQuery -> { try { filterQuery.getAccessControlContext().ifPresentOrElse( - context -> // has stored context - executes it with it - contextAware.runInContext( - context, - () -> consumer.accept(filterQuery)), - () -> // has no stored context - executes it in the tenant & user scope - contextAware.runAsTenantAsUser( - contextAware.getCurrentTenant(), - getAutoAssignmentInitiatedBy(filterQuery), () -> consumer.accept(filterQuery)) + // has stored context - executes it with it + context -> withSecurityContext(context, () -> consumer.accept(filterQuery)), + // has no stored context - executes it in the tenant & user scope + () -> asActor(getAutoAssignmentInitiatedBy(filterQuery), () -> consumer.accept(filterQuery)) ); } catch (final RuntimeException ex) { if (log.isDebugEnabled()) { @@ -173,7 +169,9 @@ public class JpaAutoAssignExecutor implements AutoAssignExecutor { final List deploymentRequests = mapToDeploymentRequests(controllerIds, targetFilterQuery); final int count = deploymentRequests.size(); if (count > 0) { - deploymentManagement.assignDistributionSets(getAutoAssignmentInitiatedBy(targetFilterQuery), deploymentRequests, actionMessage); + asActor( + getAutoAssignmentInitiatedBy(targetFilterQuery), + () -> deploymentManagement.assignDistributionSets(deploymentRequests, actionMessage)); } return count; }); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaRolloutExecutor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaRolloutExecutor.java index 4a5663a9a..0aa61b188 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaRolloutExecutor.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaRolloutExecutor.java @@ -9,6 +9,9 @@ */ package org.eclipse.hawkbit.repository.jpa.scheduler; +import static org.eclipse.hawkbit.context.AccessContext.asActor; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; +import static org.eclipse.hawkbit.context.AccessContext.withSecurityContext; import static org.eclipse.hawkbit.repository.jpa.JpaManagementHelper.combineWithAnd; import static org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor.afterCommit; @@ -25,7 +28,7 @@ import java.util.stream.StreamSupport; import jakarta.persistence.EntityManager; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.ContextAware; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.ql.jpa.QLSupport; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.QuotaManagement; @@ -73,9 +76,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.qfields.TargetFields; -import org.eclipse.hawkbit.security.SpringSecurityAuditorAware; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -127,9 +127,6 @@ public class JpaRolloutExecutor implements RolloutExecutor { private final RolloutApprovalStrategy rolloutApprovalStrategy; private final EntityManager entityManager; private final PlatformTransactionManager txManager; - private final TenantAware tenantAware; - private final ContextAware contextAware; - private final SystemSecurityContext systemSecurityContext; private final RepositoryProperties repositoryProperties; private final Map lastDynamicGroupFill = new ConcurrentHashMap<>(); @@ -142,7 +139,6 @@ public class JpaRolloutExecutor implements RolloutExecutor { final RolloutManagement rolloutManagement, final QuotaManagement quotaManagement, final RolloutGroupEvaluationManager evaluationManager, final RolloutApprovalStrategy rolloutApprovalStrategy, final EntityManager entityManager, final PlatformTransactionManager txManager, - final TenantAware tenantAware, final ContextAware contextAware, final SystemSecurityContext systemSecurityContext, final RepositoryProperties repositoryProperties) { this.actionRepository = actionRepository; this.rolloutGroupRepository = rolloutGroupRepository; @@ -157,19 +153,16 @@ public class JpaRolloutExecutor implements RolloutExecutor { this.rolloutApprovalStrategy = rolloutApprovalStrategy; this.entityManager = entityManager; this.txManager = txManager; - this.tenantAware = tenantAware; - this.contextAware = contextAware; - this.systemSecurityContext = systemSecurityContext; this.repositoryProperties = repositoryProperties; } @Override public void execute(final Rollout rollout) { rollout.getAccessControlContext().ifPresentOrElse( - 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))); + // has stored context - executes it with it + context -> withSecurityContext(context, () -> execute0(rollout)), + // has no stored context - executes it in the tenant & user scope + () -> asActor(rollout.getCreatedBy(), () -> execute0(rollout))); } private void execute0(final Rollout rollout) { @@ -184,36 +177,18 @@ public class JpaRolloutExecutor implements RolloutExecutor { break; case STARTING: // the lastModifiedBy user is probably the user that has actually called the rollout start (unless overridden) - not the creator - SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy()); - try { - handleStartingRollout((JpaRollout) rollout); - } finally { - // clear, ALWAYS, the set auditor override - SpringSecurityAuditorAware.clearAuditorOverride(); - } + asActor(rollout.getLastModifiedBy(), () -> handleStartingRollout((JpaRollout) rollout)); break; case RUNNING: handleRunningRollout((JpaRollout) rollout); break; case STOPPING: // the lastModifiedBy user is probably the user that has actually called the rollout stop (unless overridden) - not the creator - SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy()); - try { - handleStopRollout((JpaRollout) rollout); - } finally { - // clear, ALWAYS, the set auditor override - SpringSecurityAuditorAware.clearAuditorOverride(); - } + asActor(rollout.getLastModifiedBy(), () -> handleStopRollout((JpaRollout) rollout)); break; case DELETING: // the lastModifiedBy user is probably the user that has actually called the rollout delete (unless overridden) - not the creator - SpringSecurityAuditorAware.setAuditorOverride(rollout.getLastModifiedBy()); - try { - handleDeleteRollout((JpaRollout) rollout); - } finally { - // clear, ALWAYS, the set auditor override - SpringSecurityAuditorAware.clearAuditorOverride(); - } + asActor(rollout.getLastModifiedBy(), () -> handleDeleteRollout((JpaRollout) rollout)); break; default: log.error("Rollout in status {} not supposed to be handled!", rollout.getStatus()); @@ -343,12 +318,12 @@ public class JpaRolloutExecutor implements RolloutExecutor { final List groupIds = rollout.getRolloutGroups().stream().map(RolloutGroup::getId).toList(); afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher().publishEvent( - new RolloutStoppedEvent(tenantAware.getCurrentTenant(), rollout.getId(), groupIds))); + new RolloutStoppedEvent(AccessContext.tenant(), rollout.getId(), groupIds))); } } private void handleReadyRollout(final Rollout rollout) { - if (rollout.getStartAt() != null && rollout.getStartAt() <= System.currentTimeMillis()) { + if (rollout.getStartAt() != null && rollout.getStartAt() <= java.lang.System.currentTimeMillis()) { log.debug("handleReadyRollout called for rollout {} with autostart beyond define time. Switch to STARTING", rollout.getId()); rolloutManagement.start(rollout.getId()); } @@ -671,7 +646,7 @@ public class JpaRolloutExecutor implements RolloutExecutor { // return if group change is made private boolean fillDynamicRolloutGroupsWithTargets(final JpaRollout rollout) { final AtomicLong lastFill = lastDynamicGroupFill.computeIfAbsent(rollout.getId(), id -> new AtomicLong(0)); - final long now = System.currentTimeMillis(); + final long now = java.lang.System.currentTimeMillis(); if (now - lastFill.get() < repositoryProperties.getDynamicRolloutsMinInvolvePeriodMS()) { // too early to make another dynamic involvement attempt return false; @@ -873,7 +848,7 @@ public class JpaRolloutExecutor implements RolloutExecutor { try { QuotaHelper.assertAssignmentQuota(target.getId(), requested, quota, Action.class, Target.class, actionRepository::countByTargetId); } catch (final AssignmentQuotaExceededException ex) { - systemSecurityContext.runAsSystem(() -> deploymentManagement.handleMaxAssignmentsExceeded(target.getId(), requested, ex)); + asSystem(() -> deploymentManagement.handleMaxAssignmentsExceeded(target.getId(), requested, ex)); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaRolloutHandler.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaRolloutHandler.java index 122614e3c..4bf2c65cd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaRolloutHandler.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/JpaRolloutHandler.java @@ -16,12 +16,12 @@ import java.util.concurrent.locks.Lock; import io.micrometer.core.instrument.MeterRegistry; import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.RolloutExecutor; import org.eclipse.hawkbit.repository.RolloutHandler; import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.integration.support.locks.LockRegistry; import org.springframework.transaction.PlatformTransactionManager; @@ -31,7 +31,6 @@ import org.springframework.transaction.PlatformTransactionManager; @Slf4j public class JpaRolloutHandler implements RolloutHandler { - private final TenantAware tenantAware; private final RolloutManagement rolloutManagement; private final RolloutExecutor rolloutExecutor; private final LockRegistry lockRegistry; @@ -41,16 +40,14 @@ public class JpaRolloutHandler implements RolloutHandler { /** * Constructor * - * @param tenantAware the {@link TenantAware} bean holding the tenant information * @param rolloutManagement to fetch rollout related information from the datasource * @param rolloutExecutor to trigger executions for a specific rollout * @param lockRegistry to lock processes * @param txManager transaction manager interface */ - public JpaRolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement, + public JpaRolloutHandler(final RolloutManagement rolloutManagement, final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry, final PlatformTransactionManager txManager, final Optional meterRegistry) { - this.tenantAware = tenantAware; this.rolloutManagement = rolloutManagement; this.rolloutExecutor = rolloutExecutor; this.lockRegistry = lockRegistry; @@ -65,7 +62,7 @@ public class JpaRolloutHandler implements RolloutHandler { return; } - final String handlerId = createRolloutLockKey(tenantAware.getCurrentTenant()); + final String handlerId = createRolloutLockKey(AccessContext.tenant()); final Lock lock = lockRegistry.obtain(handlerId); if (!lock.tryLock()) { if (log.isTraceEnabled()) { @@ -86,7 +83,7 @@ public class JpaRolloutHandler implements RolloutHandler { } }); meterRegistry - .map(mReg -> mReg.timer("hawkbit.rollout.handler.all", DefaultTenantConfiguration.TENANT_TAG, tenantAware.getCurrentTenant())) + .map(mReg -> mReg.timer("hawkbit.rollout.handler.all", DefaultTenantConfiguration.TENANT_TAG, AccessContext.tenant())) .ifPresent(timer -> timer.record(System.nanoTime() - startNano, TimeUnit.NANOSECONDS)); log.debug("Finished handling of the rollouts."); @@ -102,7 +99,7 @@ public class JpaRolloutHandler implements RolloutHandler { return tenant + "-rollout"; } - // run in a tenant context, i.e. contextAware.getCurrentTenant() returns the tenant the rollout is made for + // run in a tenant context, i.e. Security.getCurrentTenant() returns the tenant the rollout is made for private void handleRolloutInNewTransaction(final long rolloutId, final String handlerId) { final long startNano = System.nanoTime(); @@ -116,7 +113,7 @@ public class JpaRolloutHandler implements RolloutHandler { meterRegistry .map(mReg -> mReg.timer( "hawkbit.rollout.handler", - DefaultTenantConfiguration.TENANT_TAG, tenantAware.getCurrentTenant(), + DefaultTenantConfiguration.TENANT_TAG, AccessContext.tenant(), "rollout", String.valueOf(rolloutId))) .ifPresent(timer -> timer.record(System.nanoTime() - startNano, TimeUnit.NANOSECONDS)); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/RolloutScheduler.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/RolloutScheduler.java index 7f12d1d01..b346e0715 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/RolloutScheduler.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/scheduler/RolloutScheduler.java @@ -9,6 +9,9 @@ */ package org.eclipse.hawkbit.repository.jpa.scheduler; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; + import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -17,7 +20,6 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.RolloutHandler; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.jpa.rollout.BlockWhenFullPolicy; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -34,75 +36,63 @@ public class RolloutScheduler { private final SystemManagement systemManagement; private final RolloutHandler rolloutHandler; - private final SystemSecurityContext systemSecurityContext; private final Optional meterRegistry; private final ThreadPoolTaskExecutor rolloutTaskExecutor; public RolloutScheduler( - final RolloutHandler rolloutHandler, final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext, + final RolloutHandler rolloutHandler, final SystemManagement systemManagement, final int threadPoolSize, final Optional meterRegistry) { this.systemManagement = systemManagement; this.rolloutHandler = rolloutHandler; - this.systemSecurityContext = systemSecurityContext; this.meterRegistry = meterRegistry; rolloutTaskExecutor = threadPoolTaskExecutor(threadPoolSize); } /** - * Scheduler method called by the spring-async mechanism. Retrieves all tenants from the {@link SystemManagement#findTenants} and - * runs for each tenant the {@link RolloutHandler#handleAll()} in the {@link SystemSecurityContext}. + * Scheduler method called by the spring-async mechanism. For all tenants, using {@link SystemManagement#forEachTenant}, + * runs the {@link RolloutHandler#handleAll()} scoped to permission of access control context or unscoped (with {@link System}) if null */ @Scheduled(initialDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER) public void runningRolloutScheduler() { log.debug("rollout schedule checker has been triggered."); - final long startNano = System.nanoTime(); + final long startNano = java.lang.System.nanoTime(); - // run this code in system code privileged to have the necessary - // permission to query and create entities. - systemSecurityContext.runAsSystem(() -> { - // workaround eclipselink that is currently not possible to - // execute a query without multi-tenancy if MultiTenant - // annotation is used. - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=355458. So - // iterate through all tenants and execute the rollout check for - // each tenant separately. - systemManagement.forEachTenant(tenant -> { - if (rolloutTaskExecutor == null) { - handleAll(tenant); - } else { - handleAllAsync(tenant); - } - }); - }); + // run this code in system code privileged to have the necessary system code permission execute forEachTenant + asSystem(() -> + // workaround eclipselink that is currently not possible to execute a query without multi-tenancy if MultiTenant + // annotation is used. https://bugs.eclipse.org/bugs/show_bug.cgi?id=355458. So + // iterate through all tenants and execute the rollout check for each tenant separately. + systemManagement.forEachTenant(tenant -> { + if (rolloutTaskExecutor == null) { + handleAll(tenant); + } else { + handleAllAsync(tenant); + } + })); meterRegistry .map(mReg -> mReg.timer("hawkbit.rollout.scheduler.all")) - .ifPresent(timer -> timer.record(System.nanoTime() - startNano, TimeUnit.NANOSECONDS)); + .ifPresent(timer -> timer.record(java.lang.System.nanoTime() - startNano, TimeUnit.NANOSECONDS)); } private void handleAll(final String tenant) { log.trace("Handling rollout for tenant: {}", tenant); - final long startNano = System.nanoTime(); + final long startNano = java.lang.System.nanoTime(); try { rolloutHandler.handleAll(); - } catch (Exception e) { + } catch (final Exception e) { log.error("Error processing rollout for tenant {}", tenant, e); } meterRegistry - .map(mReg -> mReg.timer( - "hawkbit.rollout.scheduler", - DefaultTenantConfiguration.TENANT_TAG, tenant)) - .ifPresent(timer -> timer.record(System.nanoTime() - startNano, TimeUnit.NANOSECONDS)); + .map(mReg -> mReg.timer("hawkbit.rollout.scheduler", DefaultTenantConfiguration.TENANT_TAG, tenant)) + .ifPresent(timer -> timer.record(java.lang.System.nanoTime() - startNano, TimeUnit.NANOSECONDS)); } private void handleAllAsync(final String tenant) { - rolloutTaskExecutor.submit(() -> systemSecurityContext.runAsSystemAsTenant(() -> { - handleAll(tenant); - return null; - }, tenant)); + rolloutTaskExecutor.submit(() -> asSystemAsTenant(tenant, () -> handleAll(tenant))); } private ThreadPoolTaskExecutor threadPoolTaskExecutor(final int threadPoolSize) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/ActionSpecifications.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/ActionSpecifications.java index 842512849..d51ba0d0d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/ActionSpecifications.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/ActionSpecifications.java @@ -9,6 +9,8 @@ */ package org.eclipse.hawkbit.repository.jpa.specifications; +import java.util.List; + import jakarta.persistence.criteria.Join; import jakarta.persistence.criteria.ListJoin; import jakarta.persistence.criteria.SetJoin; @@ -29,8 +31,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.model.Action; import org.springframework.data.jpa.domain.Specification; -import java.util.List; - /** * Utility class for {@link Action}s {@link Specification}s. The class provides Spring Data JPQL Specifications. */ diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetTypeSpecification.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetTypeSpecification.java index 9ad134486..16aa6cd09 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetTypeSpecification.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetTypeSpecification.java @@ -11,10 +11,8 @@ package org.eclipse.hawkbit.repository.jpa.specifications; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaNamedEntity_; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTypeEntity_; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; -import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType_; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.springframework.data.jpa.domain.Specification; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/utils/WeightValidationHelper.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/utils/WeightValidationHelper.java index c0fa02d14..baca08f65 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/utils/WeightValidationHelper.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/utils/WeightValidationHelper.java @@ -11,46 +11,25 @@ package org.eclipse.hawkbit.repository.jpa.utils; import java.util.List; +import lombok.NoArgsConstructor; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.NoWeightProvidedInMultiAssignmentModeException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.DeploymentRequest; import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.utils.TenantConfigHelper; /** - * Utility class to handle weight validation in Rollout, Auto Assignments, and - * Online Assignment. + * Utility class to handle weight validation in Rollout, Auto Assignments, and Online Assignment. */ +@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE) public final class WeightValidationHelper { - private final TenantConfigurationManagement tenantConfigurationManagement; - private final SystemSecurityContext systemSecurityContext; - - private WeightValidationHelper( - 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 - */ - public static WeightValidationHelper usingContext( - final SystemSecurityContext systemSecurityContext, final TenantConfigurationManagement tenantConfigurationManagement) { - return new WeightValidationHelper(systemSecurityContext, tenantConfigurationManagement); - } - /** * Validating weights associated with all the {@link DeploymentRequest}s * * @param deploymentRequests the {@linkplain List} of {@link DeploymentRequest}s */ - public void validate(final List deploymentRequests) { + public static void validate(final List deploymentRequests) { final long assignmentsWithWeight = deploymentRequests.stream() .filter(request -> request.getTargetWithActionType().getWeight() != null).count(); final boolean containsAssignmentWithWeight = assignmentsWithWeight > 0; @@ -64,7 +43,7 @@ public final class WeightValidationHelper { * * @param rollout the {@linkplain Rollout} */ - public void validate(final Rollout rollout) { + public static void validate(final Rollout rollout) { validateWeight(rollout.getWeight().orElse(null)); } @@ -73,7 +52,7 @@ public final class WeightValidationHelper { * * @param targetFilterQueryCreate the target filter query */ - public void validate(final TargetFilterQueryManagement.Create targetFilterQueryCreate) { + public static void validate(final TargetFilterQueryManagement.Create targetFilterQueryCreate) { validateWeight(targetFilterQueryCreate.getAutoAssignWeight()); } @@ -82,7 +61,7 @@ public final class WeightValidationHelper { * * @param autoAssignDistributionSetUpdate the auto assignment distribution set update */ - public void validate(final TargetFilterQueryManagement.AutoAssignDistributionSetUpdate autoAssignDistributionSetUpdate) { + public static void validate(final TargetFilterQueryManagement.AutoAssignDistributionSetUpdate autoAssignDistributionSetUpdate) { validateWeight(autoAssignDistributionSetUpdate.weight()); } @@ -91,7 +70,7 @@ public final class WeightValidationHelper { * * @param weight weight tied to the rollout, auto assignment, or online assignment. */ - public void validateWeight(final Integer weight) { + public static void validateWeight(final Integer weight) { final boolean hasWeight = weight != null; validateWeight(hasWeight, !hasWeight); } @@ -102,15 +81,11 @@ public final class WeightValidationHelper { * @param hasWeight indicator of the weight if it has numerical value * @param hasNoWeight indicator of the weight if it doesn't have a numerical value */ - public void validateWeight(final boolean hasWeight, final boolean hasNoWeight) { + public static void validateWeight(final boolean hasWeight, final boolean hasNoWeight) { // remove bypassing the weight enforcement as soon as weight can be set via UI final boolean bypassWeightEnforcement = true; - final boolean multiAssignmentsEnabled = TenantConfigHelper - .usingContext(systemSecurityContext, tenantConfigurationManagement) - .isMultiAssignmentsEnabled(); - if (bypassWeightEnforcement) { - return; - } else if (multiAssignmentsEnabled && hasNoWeight) { + final boolean multiAssignmentsEnabled = TenantConfigHelper.isMultiAssignmentsEnabled(); + if (!bypassWeightEnforcement && multiAssignmentsEnabled && hasNoWeight) { throw new NoWeightProvidedInMultiAssignmentModeException(); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/ql/rsql/RsqlActionFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/ql/rsql/RsqlActionFieldsTest.java index 0aeb1054d..6ab5e95f4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/ql/rsql/RsqlActionFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/ql/rsql/RsqlActionFieldsTest.java @@ -12,6 +12,7 @@ package org.eclipse.hawkbit.ql.rsql; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.TargetManagement.Create; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; @@ -117,7 +118,7 @@ class RsqlActionFieldsTest extends AbstractJpaIntegrationTest { newAction.setStatus(active ? Status.RUNNING : Status.FINISHED); newAction.setTarget(target); newAction.setWeight(45); - newAction.setInitiatedBy(tenantAware.getCurrentUsername()); + newAction.setInitiatedBy(AccessContext.actor()); if (extRef != null) { newAction.setExternalRef(extRef); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/ql/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/ql/rsql/VirtualPropertyResolverTest.java index 15b89166b..a6f0bcac9 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/ql/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/ql/rsql/VirtualPropertyResolverTest.java @@ -12,23 +12,16 @@ package org.eclipse.hawkbit.ql.rsql; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; -import java.util.concurrent.Callable; - import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -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.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.Mockito; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -45,18 +38,17 @@ class VirtualPropertyResolverTest { TenantConfigurationValue. builder().value("00:07:37").build(); @MockitoBean - private TenantConfigurationManagement confMgmt; - @MockitoBean - private SystemSecurityContext securityContext; + private TenantConfigurationManagement tenantConfigurationManagement; private final VirtualPropertyResolver substitutor = new VirtualPropertyResolver(); @BeforeEach void before() { - when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME, String.class)) + when(tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.POLLING_TIME, String.class)) .thenReturn(TEST_POLLING_TIME_INTERVAL); - when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME, String.class)) + when(tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME, String.class)) .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); + TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagement); } /** @@ -90,24 +82,9 @@ class VirtualPropertyResolverTest { @ParameterizedTest @ValueSource(strings = { "${NOW_TS}", "${OVERDUE_TS}", "${overdue_ts}" }) void resolveNowTimestampPlaceholder(final String placeholder) { - when(securityContext.runAsSystem(Mockito.any(Callable.class))).thenAnswer(a -> ((Callable) a.getArgument(0)).call()); final String testString = "lhs=lt=" + placeholder; final String resolvedPlaceholders = substitutor.replace(testString); assertThat(resolvedPlaceholders).as("'%s' placeholder was not replaced", placeholder).doesNotContain(placeholder); } - - @Configuration - static class Config { - - @Bean - TenantConfigurationManagementHolder tenantConfigurationManagementHolder() { - return TenantConfigurationManagementHolder.getInstance(); - } - - @Bean - SystemSecurityContextHolder systemSecurityContextHolder() { - return SystemSecurityContextHolder.getInstance(); - } - } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/AbstractRemoteEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/AbstractRemoteEventTest.java index edc1999db..69a931135 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/AbstractRemoteEventTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/AbstractRemoteEventTest.java @@ -8,7 +8,9 @@ * SPDX-License-Identifier: EPL-2.0 */ package org.eclipse.hawkbit.repository.event.remote; + import java.util.Map; + import org.eclipse.hawkbit.event.EventJacksonMessageConverter; import org.eclipse.hawkbit.event.EventProtoStuffMessageConverter; import org.eclipse.hawkbit.repository.event.TenantAwareEvent; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/RemoteTenantAwareEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/RemoteTenantEventTest.java similarity index 97% rename from hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/RemoteTenantAwareEventTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/RemoteTenantEventTest.java index a6d9e36b1..07c7a25a6 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/RemoteTenantAwareEventTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/RemoteTenantEventTest.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.List; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; @@ -25,7 +26,7 @@ import org.junit.jupiter.api.Test; * Feature: Component Tests - Repository
* Story: RemoteTenantAwareEvent Tests */ -class RemoteTenantAwareEventTest extends AbstractRemoteEventTest { +class RemoteTenantEventTest extends AbstractRemoteEventTest { private static final String TENANT_DEFAULT = "DEFAULT"; @@ -93,7 +94,7 @@ class RemoteTenantAwareEventTest extends AbstractRemoteEventTest { generateAction.setTarget(testdataFactory.createTarget("Test")); generateAction.setDistributionSet(dsA); generateAction.setStatus(Status.RUNNING); - generateAction.setInitiatedBy(tenantAware.getCurrentUsername()); + generateAction.setInitiatedBy(AccessContext.actor()); generateAction.setWeight(1000); final Action action = actionRepository.save(generateAction); @@ -120,7 +121,7 @@ class RemoteTenantAwareEventTest extends AbstractRemoteEventTest { generateAction.setTarget(testdataFactory.createTarget("Test")); generateAction.setDistributionSet(dsA); generateAction.setStatus(Status.RUNNING); - generateAction.setInitiatedBy(tenantAware.getCurrentUsername()); + generateAction.setInitiatedBy(AccessContext.actor()); generateAction.setWeight(1000); final Action action = actionRepository.save(generateAction); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/ServiceEventsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/ServiceEventsTest.java index a1ab00f2f..ff2ed73af 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/ServiceEventsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/ServiceEventsTest.java @@ -9,6 +9,16 @@ */ package org.eclipse.hawkbit.repository.event.remote; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Set; + import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent; @@ -28,12 +38,6 @@ import org.junit.jupiter.api.Test; import org.springframework.cloud.stream.function.StreamBridge; import org.springframework.context.ApplicationEventPublisher; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.Set; - class ServiceEventsTest { private StreamBridge streamBridge; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionEventTest.java index 23935ff5d..196a92959 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionEventTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionEventTest.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity; import static org.assertj.core.api.Assertions.assertThat; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; @@ -86,7 +87,7 @@ class ActionEventTest extends AbstractRemoteEntityEventTest { generateAction.setTarget(target); generateAction.setDistributionSet(distributionSet); generateAction.setStatus(Status.RUNNING); - generateAction.setInitiatedBy(tenantAware.getCurrentUsername()); + generateAction.setInitiatedBy(AccessContext.actor()); generateAction.setWeight(1000); return actionRepository.save(generateAction); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java index 6c535d05a..2e8b0c2db 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java @@ -16,6 +16,7 @@ import java.util.Collection; import java.util.List; import java.util.Set; import java.util.stream.StreamSupport; + import lombok.extern.slf4j.Slf4j; import org.assertj.core.api.Assertions; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; @@ -29,10 +30,10 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository; +import org.eclipse.hawkbit.repository.jpa.repository.ArtifactRepository; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository; -import org.eclipse.hawkbit.repository.jpa.repository.ArtifactRepository; import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository; import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository; import org.eclipse.hawkbit.repository.jpa.repository.RolloutTargetGroupRepository; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ConcurrentDistributionSetInvalidationTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ConcurrentDistributionSetInvalidationTest.java index 410b119f1..14189c252 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ConcurrentDistributionSetInvalidationTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ConcurrentDistributionSetInvalidationTest.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant; import static org.mockito.AdditionalAnswers.delegatesTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; @@ -20,6 +21,7 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; import org.awaitility.Awaitility; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.RolloutManagement.Create; import org.eclipse.hawkbit.repository.exception.StopRolloutException; import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; @@ -59,23 +61,17 @@ class ConcurrentDistributionSetInvalidationTest extends AbstractJpaIntegrationTe void verifyInvalidateDistributionSetWithLargeRolloutThrowsException() { final DistributionSet distributionSet = testdataFactory.createDistributionSet(); final Rollout rollout = createRollout(distributionSet); - final String tenant = tenantAware.getCurrentTenant(); + final String tenant = AccessContext.tenant(); // run in new Thread so that the invalidation can be executed in // parallel - new Thread(() -> systemSecurityContext.runAsSystemAsTenant(() -> { - rolloutHandler.handleAll(); - return 0; - }, tenant)).start(); + new Thread(() -> asSystemAsTenant(tenant, rolloutHandler::handleAll)).start(); // wait until at least one RolloutGroup is created, as this means that the thread has started and has acquired the lock Awaitility.await() .pollInterval(Duration.ofMillis(100)) .atMost(Duration.ofSeconds(5)) - .until(() -> tenantAware.runAsTenant( - tenant, - () -> systemSecurityContext.runAsSystem( - () -> rolloutGroupManagement.findByRollout(rollout.getId(), PAGE).getSize() > 0))); + .until(() -> asSystemAsTenant(tenant, () -> rolloutGroupManagement.findByRollout(rollout.getId(), PAGE).getSize() > 0)); final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation( Collections.singletonList(distributionSet.getId()), ActionCancellationType.SOFT); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/ActionAccessControllerTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/ActionAccessControllerTest.java index 8b12ee27d..68da5f64c 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/ActionAccessControllerTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/ActionAccessControllerTest.java @@ -10,7 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.acm; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.withUser; @@ -24,7 +24,6 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; @TestPropertySource(properties = "hawkbit.acm.access-controller.enabled=true") diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/AutoAssignTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/AutoAssignTest.java index 23daf866e..c415ee05e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/AutoAssignTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/AutoAssignTest.java @@ -10,19 +10,19 @@ package org.eclipse.hawkbit.repository.jpa.acm; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.im.authentication.SpPermission.CREATE_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DELETE_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_DISTRIBUTION_SET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.DELETE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_TARGET; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.callAs; import java.util.Optional; +import org.eclipse.hawkbit.repository.AutoAssignExecutor; import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.AutoAssignDistributionSetUpdate; -import org.eclipse.hawkbit.repository.AutoAssignExecutor; import org.eclipse.hawkbit.repository.jpa.scheduler.AutoAssignScheduler; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.junit.jupiter.api.Test; @@ -41,8 +41,7 @@ class AutoAssignTest extends AbstractAccessControllerManagementTest { void verifyOnlyUpdatableTargetsArePartOfAutoAssignmentByScheduler() throws Exception { // auto assign scheduler apply stored access control context and the context is correctly applied verifyOnlyUpdatableTargetsArePartOfAutoAssignment( - () -> new AutoAssignScheduler(systemManagement, systemSecurityContext, autoAssignExecutor, lockRegistry, Optional.empty()) - .autoAssignScheduler()); + () -> new AutoAssignScheduler(systemManagement, autoAssignExecutor, lockRegistry, Optional.empty()).autoAssignScheduler()); } @Test diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DeploymentManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DeploymentManagementTest.java index 39ebd91ad..559fe3b20 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DeploymentManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DeploymentManagementTest.java @@ -13,9 +13,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatNoException; 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_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_TARGET; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import java.util.List; @@ -39,7 +40,7 @@ class DeploymentManagementTest extends AbstractAccessControllerManagementTest { READ_DISTRIBUTION_SET), () -> assertThat(deploymentManagement.assignDistributionSets(List.of(new DeploymentRequest( target1Type1.getControllerId(), ds1Type1.getId(), Action.ActionType.FORCED, 0, - null, null, null, null, false))) + null, null, null, null, false)), null) .get(0).getAssignedEntity().stream().map(Action::getTarget) .map(Target::getId)) .hasSize(1) @@ -51,7 +52,7 @@ class DeploymentManagementTest extends AbstractAccessControllerManagementTest { READ_DISTRIBUTION_SET), () -> assertThat(deploymentManagement.assignDistributionSets(List.of(new DeploymentRequest( target1Type1.getControllerId(), ds1Type1.getId(), Action.ActionType.FORCED, 0, - null, null, null, null, false)))).isEmpty()); + null, null, null, null, false)), null)).isEmpty()); } @Test @@ -191,7 +192,7 @@ class DeploymentManagementTest extends AbstractAccessControllerManagementTest { } private void verify(final Consumer noRead, final Consumer readNoUpdate, final Consumer readAndUpdate) { - final Long actionId = systemSecurityContext.runAsSystem(() -> { + final Long actionId = asSystem(() -> { final List actions = assignDistributionSet(ds1Type1.getId(), target1Type1.getControllerId()).getAssignedEntity(); assertThat(actions).hasSize(1).allMatch(action -> action.getTarget().getId().equals(target1Type1.getId())); return actions.get(0); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DistributionSetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DistributionSetManagementTest.java index 15818bc4f..53b073779 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DistributionSetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DistributionSetManagementTest.java @@ -12,10 +12,10 @@ package org.eclipse.hawkbit.repository.jpa.acm; 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_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DISTRIBUTION_SET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_DISTRIBUTION_SET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_DISTRIBUTION_SET; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import java.util.List; @@ -157,7 +157,7 @@ class DistributionSetManagementTest extends AbstractAccessControllerManagementTe assertThat(ds1Type1).matches(updated -> updated.getModules().stream() .map(Identifiable::getId).anyMatch(sm1Type1.getId()::equals)); try { - SecurityContextSwitch.callAsPrivileged(() -> distributionSetManagement.unlock(ds2Type2)); + SecurityContextSwitch.asPrivileged(() -> distributionSetManagement.unlock(ds2Type2)); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DistributionSetTypeManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DistributionSetTypeManagementTest.java index 10c74d3fa..de7c00134 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DistributionSetTypeManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/DistributionSetTypeManagementTest.java @@ -12,11 +12,11 @@ package org.eclipse.hawkbit.repository.jpa.acm; 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_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DELETE_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DISTRIBUTION_SET_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.DELETE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.DISTRIBUTION_SET_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.READ_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_PREFIX; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import java.util.List; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/RolloutExecutionTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/RolloutExecutionTest.java index b9860f5b3..cb423d280 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/RolloutExecutionTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/RolloutExecutionTest.java @@ -10,12 +10,13 @@ package org.eclipse.hawkbit.repository.jpa.acm; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.im.authentication.SpPermission.CREATE_ROLLOUT; -import static org.eclipse.hawkbit.im.authentication.SpPermission.HANDLE_ROLLOUT; -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; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_ROLLOUT; +import static org.eclipse.hawkbit.auth.SpPermission.HANDLE_ROLLOUT; +import static org.eclipse.hawkbit.auth.SpPermission.READ_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_ROLLOUT; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_TARGET; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import java.util.Arrays; @@ -31,12 +32,12 @@ class RolloutExecutionTest extends AbstractAccessControllerManagementTest { @Test void verifyOnlyUpdatableTargetsArePartOfRolloutExecutedByScheduler() { - verify(new RolloutScheduler(rolloutHandler, systemManagement, systemSecurityContext, 1, Optional.empty())::runningRolloutScheduler); + verify(new RolloutScheduler(rolloutHandler, systemManagement, 1, Optional.empty())::runningRolloutScheduler); } @Test void verifyOnlyUpdatableTargetsArePartOfRollout() { - verify(() -> systemSecurityContext.runAsSystem(rolloutHandler::handleAll)); + verify(() -> asSystem(rolloutHandler::handleAll)); } private void verify(final Runnable run) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/RolloutManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/RolloutManagementTest.java index 154360e0f..2345e144c 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/RolloutManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/RolloutManagementTest.java @@ -10,8 +10,8 @@ package org.eclipse.hawkbit.repository.jpa.acm; import static org.assertj.core.api.Assertions.assertThat; -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.auth.SpPermission.READ_ROLLOUT; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET; import static org.eclipse.hawkbit.repository.model.TotalTargetCountStatus.Status.NOTSTARTED; import static org.eclipse.hawkbit.repository.model.TotalTargetCountStatus.Status.RUNNING; import static org.eclipse.hawkbit.repository.model.TotalTargetCountStatus.Status.SCHEDULED; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/ContextAwareTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SecurityContextCtxTest.java similarity index 50% rename from hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/ContextAwareTest.java rename to hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SecurityContextCtxTest.java index 7f1412e91..1f7c0e185 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/ContextAwareTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SecurityContextCtxTest.java @@ -10,86 +10,54 @@ package org.eclipse.hawkbit.repository.jpa.acm; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.security.SecurityContextSerializer.JSON_SERIALIZATION; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.mockStatic; import java.util.Set; import java.util.concurrent.Callable; +import java.util.function.Supplier; import lombok.SneakyThrows; -import org.eclipse.hawkbit.ContextAware; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.AutoAssignExecutor; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; -import org.eclipse.hawkbit.security.SecurityContextSerializer; import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.domain.AuditorAware; import org.springframework.data.domain.Pageable; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.test.context.ContextConfiguration; /** * Feature: Component Tests - Context runner
* Story: Test Context Runner */ -@ContextConfiguration(classes = { ContextAwareTest.TestConfiguration.class }) -class ContextAwareTest extends AbstractJpaIntegrationTest { +class SecurityContextCtxTest extends AbstractJpaIntegrationTest { private static final Set AUTHORITIES = SpPermission.getAllAuthorities(); @Autowired AutoAssignExecutor autoAssignExecutor; - @Autowired - ContextAware contextAware; - - @Autowired - AuditorAware auditorAware; - - @BeforeEach - @AfterEach - void before() { - reset(contextAware); - } - /** * Verifies acm context is persisted when creating Rollout */ @Test void verifyAcmContextIsPersistedInCreatedRollout() { - final SecurityContext securityContext = createContext(0); - assertThat(securityContext).isNotNull(); + final SecurityContext userContext = createUserContext(0); + assertThat(userContext).isNotNull(); - final Rollout exampleRollout = runInContext(securityContext, testdataFactory::createRollout); + final Rollout exampleRollout = withSecurityContext(userContext, testdataFactory::createRollout); assertThat(exampleRollout.getAccessControlContext()) - .hasValueSatisfying(ctx -> assertEssentialEquals(JSON_SERIALIZATION.deserialize(ctx), securityContext)); - } - - /** - * Verifies acm context is reused when handling a rollout - */ - @Test - void verifyContextIsReusedWhenHandlingRollout() { - final SecurityContext securityContext = createContext(1); - - // testdataFactory#createRollout will trigger a rollout handling - runInContext(securityContext, testdataFactory::createRollout); - verify(contextAware).runInContext(eq(JSON_SERIALIZATION.serialize(securityContext)), any(Runnable.class)); + .hasValueSatisfying(ctx -> assertEssentialEquals(deserialize(ctx), userContext)); } /** @@ -97,59 +65,82 @@ class ContextAwareTest extends AbstractJpaIntegrationTest { */ @Test void verifyContextIsPersistedInActiveAutoAssignment() { - final SecurityContext securityContext = createContext(2); + final SecurityContext userContext = createUserContext(2); final TargetFilterQuery targetFilterQuery = - runInContext(securityContext, testdataFactory::createTargetFilterWithTargetsAndActiveAutoAssignment); + withSecurityContext(userContext, testdataFactory::createTargetFilterWithTargetsAndActiveAutoAssignment); assertThat(targetFilterQuery.getAccessControlContext()) - .hasValueSatisfying(ctx -> assertEssentialEquals(JSON_SERIALIZATION.deserialize(ctx), securityContext)); + .hasValueSatisfying(ctx -> assertEssentialEquals(deserialize(ctx), userContext)); + } + + /** + * Verifies acm context is used when handling a rollout + */ + @Test + void verifyContextIsUsedWhenHandlingRollout() { + final SecurityContext userContext = createUserContext(1); + final String serialized = serialize(userContext); + try (final MockedStatic mocked = mockStatic(AccessContext.class, Mockito.CALLS_REAL_METHODS)) { + // testdataFactory#createRollout will trigger a rollout handling + withSecurityContext(userContext, testdataFactory::createRollout); + mocked.verify(() -> AccessContext.withSecurityContext(eq(serialized), any(Runnable.class))); + } } /** * Verifies acm context is used when performing auto assign check on all target */ @Test - void verifyContextIsReusedWhenCheckingForAutoAssignmentAllTargets() { - final SecurityContext securityContext = createContext(3); + void verifyContextIsUsedWhenCheckingForAutoAssignmentAllTargets() { + final SecurityContext userContext = createUserContext(3); + final String serialized = serialize(userContext); + try (final MockedStatic mocked = mockStatic(AccessContext.class, Mockito.CALLS_REAL_METHODS)) { + withSecurityContext(userContext, testdataFactory::createTargetFilterWithTargetsAndActiveAutoAssignment); + withSecurityContext(userContext, () -> { + autoAssignExecutor.checkAllTargets(); + return null; + }); - runInContext(securityContext, testdataFactory::createTargetFilterWithTargetsAndActiveAutoAssignment); - runInContext(securityContext, () -> { - autoAssignExecutor.checkAllTargets(); - return null; - }); - verify(contextAware).runInContext(eq(JSON_SERIALIZATION.serialize(securityContext)), any(Runnable.class)); + mocked.verify(() -> AccessContext.withSecurityContext(eq(serialized), any(Runnable.class))); + } } /** * Verifies acm context is used when performing auto assign check on single target */ @Test - void verifyContextIsReusedWhenCheckingForAutoAssignmentSingleTarget() { - final SecurityContext securityContext = createContext(4); + void verifyContextIsUsedWhenCheckingForAutoAssignmentSingleTarget() { + final SecurityContext userContext = createUserContext(4); + final String serialized = serialize(userContext); + try (final MockedStatic mocked = mockStatic(AccessContext.class, Mockito.CALLS_REAL_METHODS)) { + mocked.when(() -> AccessContext.withSecurityContext(any(SecurityContext.class), (Supplier) any(Supplier.class))) + .thenCallRealMethod(); - runInContext(securityContext, testdataFactory::createTargetFilterWithTargetsAndActiveAutoAssignment); - runInContext(securityContext, () -> { - autoAssignExecutor.checkSingleTarget(targetManagement.findAll(Pageable.ofSize(1)).getContent().get(0).getControllerId()); - return null; - }); - verify(contextAware).runInContext(eq(JSON_SERIALIZATION.serialize(securityContext)), any(Runnable.class)); + withSecurityContext(userContext, testdataFactory::createTargetFilterWithTargetsAndActiveAutoAssignment); + withSecurityContext(userContext, () -> { + autoAssignExecutor.checkSingleTarget(targetManagement.findAll(Pageable.ofSize(1)).getContent().get(0).getControllerId()); + return null; + }); + + mocked.verify(() -> AccessContext.withSecurityContext(eq(serialized), any(Runnable.class))); + } } - private static SecurityContext createContext(final int testId) { - final SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + private static SecurityContext createUserContext(final int testId) { + final SecurityContext userContext = SecurityContextHolder.createEmptyContext(); final UsernamePasswordAuthenticationToken userPassAuthentication = new UsernamePasswordAuthenticationToken( "user", null, AUTHORITIES.stream().map(SimpleGrantedAuthority::new).toList()); final TenantAwareAuthenticationDetails details = new TenantAwareAuthenticationDetails("my_tenant_" + testId, false); userPassAuthentication.setDetails(details); - securityContext.setAuthentication(userPassAuthentication); + userContext.setAuthentication(userPassAuthentication); - assertThat(securityContext).isNotNull(); + assertThat(userContext).isNotNull(); - return securityContext; + return userContext; } @SneakyThrows - private T runInContext(final SecurityContext securityContext, final Callable runnable) { + private T withSecurityContext(final SecurityContext securityContext, final Callable runnable) { SecurityContextHolder.setContext(securityContext); try { return runnable.call(); @@ -168,19 +159,17 @@ class ContextAwareTest extends AbstractJpaIntegrationTest { private String auditor(final SecurityContext securityContext) { SecurityContextHolder.setContext(securityContext); try { - return auditorAware.getCurrentAuditor().orElseThrow(); + return AccessContext.actor(); } finally { SecurityContextHolder.clearContext(); } } - @Configuration - static class TestConfiguration { + private static String serialize(final SecurityContext securityContext) { + return AccessContext.withSecurityContext(securityContext, () -> AccessContext.securityContext().orElseThrow()); + } - @Bean - @ConditionalOnMissingBean - SecurityContextSerializer securityContextSerializer() { - return SecurityContextSerializer.JSON_SERIALIZATION; - } + private static SecurityContext deserialize(final String serialized) { + return AccessContext.withSecurityContext(serialized, SecurityContextHolder::getContext); } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SoftwareModuleManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SoftwareModuleManagementTest.java index 202897b28..4eb7787a0 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SoftwareModuleManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SoftwareModuleManagementTest.java @@ -12,9 +12,9 @@ package org.eclipse.hawkbit.repository.jpa.acm; 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_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.SOFTWARE_MODULE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.READ_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.SOFTWARE_MODULE; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_PREFIX; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SoftwareModuleTypeManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SoftwareModuleTypeManagementTest.java index 2a9ef95ef..c2ee55416 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SoftwareModuleTypeManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SoftwareModuleTypeManagementTest.java @@ -12,11 +12,11 @@ package org.eclipse.hawkbit.repository.jpa.acm; 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_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DELETE_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.SOFTWARE_MODULE_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.DELETE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.READ_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.SOFTWARE_MODULE_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_PREFIX; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import java.util.List; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SystemExecutionTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SystemExecutionTest.java index b57d4b519..d73752715 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SystemExecutionTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/SystemExecutionTest.java @@ -10,19 +10,20 @@ package org.eclipse.hawkbit.repository.jpa.acm; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.im.authentication.SpPermission.CREATE_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DELETE_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DELETE_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DISTRIBUTION_SET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DISTRIBUTION_SET_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_DISTRIBUTION_SET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.SOFTWARE_MODULE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.SOFTWARE_MODULE_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.TARGET_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.DELETE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.DELETE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.DISTRIBUTION_SET_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.READ_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.SOFTWARE_MODULE; +import static org.eclipse.hawkbit.auth.SpPermission.SOFTWARE_MODULE_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.TARGET_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_TARGET; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -101,6 +102,7 @@ class SystemExecutionTest extends AbstractAccessControllerManagementTest { private void verifyAccessController(final AccessController accessController) { verifyAccessController(accessController, 1); } + @SuppressWarnings({ "rawtypes", "unchecked" }) private void verifyAccessController(final AccessController accessController, final int times) { final Specification mock = mock(Specification.class); @@ -110,8 +112,8 @@ class SystemExecutionTest extends AbstractAccessControllerManagementTest { verify(mock, times(times)).and(any()); // once for every access controller is scoped only final Specification mockAsSystem = mock(Specification.class); - for (Operation operation : Operation.values()) { - systemSecurityContext.runAsSystem(() -> accessController.appendAccessRules(operation, mockAsSystem)); + for (final Operation operation : Operation.values()) { + asSystem(() -> accessController.appendAccessRules(operation, mockAsSystem)); } verifyNoInteractions(mockAsSystem); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetManagementTest.java index c8a661bea..b9f0e7c23 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetManagementTest.java @@ -12,14 +12,15 @@ package org.eclipse.hawkbit.repository.jpa.acm; 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.CREATE_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DELETE_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.HANDLE_ROLLOUT; -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; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_ROLLOUT; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.DELETE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.HANDLE_ROLLOUT; +import static org.eclipse.hawkbit.auth.SpPermission.READ_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_ROLLOUT; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_TARGET; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import java.util.Arrays; @@ -169,9 +170,8 @@ class TargetManagementTest extends AbstractAccessControllerManagementTest { .containsExactly(target1Type1); // as system in context - doesn't apply scopes - final Rollout runAsSystem = systemSecurityContext.runAsSystem( - () -> testdataFactory.createRolloutByVariables( - "testRolloutAsSystem", "testDescriptionAsSystem", 3, "id==*", ds2Type2, "50", "5")); + asSystem(() -> testdataFactory.createRolloutByVariables( + "testRolloutAsSystem", "testDescriptionAsSystem", 3, "id==*", ds2Type2, "50", "5")); }); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetTypeManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetTypeManagementTest.java index b0ccfe2e9..898a9c905 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetTypeManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetTypeManagementTest.java @@ -12,13 +12,13 @@ package org.eclipse.hawkbit.repository.jpa.acm; 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_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DELETE_TARGET_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.DISTRIBUTION_SET_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_PREFIX; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_TARGET_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.TARGET_TYPE; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_TARGET_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.CREATE_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.DELETE_TARGET_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.DISTRIBUTION_SET_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.READ_PREFIX; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.TARGET_TYPE; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_TARGET_TYPE; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import java.util.Collections; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetTypeQueryManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetTypeQueryManagementTest.java index c32faba41..2542fe005 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetTypeQueryManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/acm/TargetTypeQueryManagementTest.java @@ -11,10 +11,10 @@ package org.eclipse.hawkbit.repository.jpa.acm; import static org.assertj.core.api.Assertions.assertThat; 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_TARGET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_DISTRIBUTION_SET; -import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TARGET; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_DISTRIBUTION_SET; +import static org.eclipse.hawkbit.auth.SpPermission.UPDATE_TARGET; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoActionCleanupTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoActionCleanupTest.java index e1724ea87..65f6a7b35 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoActionCleanupTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoActionCleanupTest.java @@ -206,9 +206,8 @@ class AutoActionCleanupTest extends AbstractJpaIntegrationTest { } private void setupCleanupConfiguration(final long expiry, final Status... status) { - tenantConfigurationManagement.addOrUpdateConfiguration(ACTION_CLEANUP_AUTO_EXPIRY, expiry); - tenantConfigurationManagement.addOrUpdateConfiguration( - ACTION_CLEANUP_AUTO_STATUS, - Arrays.stream(status).map(Status::toString).collect(Collectors.joining(","))); + tenantConfigurationManagement().addOrUpdateConfiguration(ACTION_CLEANUP_AUTO_EXPIRY, expiry); + tenantConfigurationManagement().addOrUpdateConfiguration( + ACTION_CLEANUP_AUTO_STATUS, Arrays.stream(status).map(Status::toString).collect(Collectors.joining(","))); } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoCleanupSchedulerTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoCleanupSchedulerTest.java index d5b72dd09..2b9cdd5ae 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoCleanupSchedulerTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/autocleanup/AutoCleanupSchedulerTest.java @@ -47,7 +47,7 @@ class AutoCleanupSchedulerTest extends AbstractJpaIntegrationTest { void executeHandlerChain() { new AutoCleanupScheduler( List.of(new SuccessfulCleanup(), new SuccessfulCleanup(), new FailingCleanup(), new SuccessfulCleanup()), - systemManagement, systemSecurityContext, lockRegistry).run(); + systemManagement, lockRegistry).run(); assertThat(counter.get()).isEqualTo(4); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ArtifactManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ArtifactManagementTest.java index c663b2ab9..a14b9fee7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ArtifactManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ArtifactManagementTest.java @@ -31,8 +31,9 @@ import org.eclipse.hawkbit.artifact.exception.FileSizeQuotaExceededException; import org.eclipse.hawkbit.artifact.exception.StorageQuotaExceededException; import org.eclipse.hawkbit.artifact.model.ArtifactHashes; import org.eclipse.hawkbit.artifact.model.ArtifactStream; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.auth.SpRole; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; @@ -252,7 +253,7 @@ class ArtifactManagementTest extends AbstractJpaIntegrationTest { assertThat(artifact2.getId()).isNotNull(); assertThat(artifact1.getSha1Hash()).isNotEqualTo(artifact2.getSha1Hash()); - final String currentTenant = tenantAware.getCurrentTenant(); + final String currentTenant = AccessContext.tenant(); assertThat(artifactStorage.getBySha1(currentTenant, artifact1.getSha1Hash())).isNotNull(); assertThat(artifactStorage.getBySha1(currentTenant, artifact2.getSha1Hash())).isNotNull(); @@ -296,7 +297,7 @@ class ArtifactManagementTest extends AbstractJpaIntegrationTest { assertThat(artifact2.getId()).isNotNull(); assertThat((artifact1).getSha1Hash()).isEqualTo(artifact2.getSha1Hash()); assertThat(artifactRepository.findAll()).hasSize(2); - final String currentTenant = tenantAware.getCurrentTenant(); + final String currentTenant = AccessContext.tenant(); assertThat(artifactStorage.getBySha1(currentTenant, artifact1.getSha1Hash())).isNotNull(); artifactManagement.delete(artifact1.getId()); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ControllerManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ControllerManagementTest.java index dde2b9114..d3466a592 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ControllerManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ControllerManagementTest.java @@ -12,8 +12,9 @@ package org.eclipse.hawkbit.repository.jpa.management; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatNoException; -import static org.eclipse.hawkbit.im.authentication.SpRole.CONTROLLER_ROLE; -import static org.eclipse.hawkbit.im.authentication.SpRole.CONTROLLER_ROLE_ANONYMOUS; +import static org.eclipse.hawkbit.auth.SpRole.CONTROLLER_ROLE; +import static org.eclipse.hawkbit.auth.SpRole.CONTROLLER_ROLE_ANONYMOUS; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_MAX; import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY; import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.runAs; @@ -36,7 +37,7 @@ import java.util.stream.IntStream; import jakarta.validation.ConstraintViolationException; import org.assertj.core.api.Assertions; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.UpdateMode; @@ -203,12 +204,12 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest { final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget)); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId) - .status(Action.Status.RUNNING).timestamp(System.currentTimeMillis()).messages(List.of("proceeding message 1")) + .status(Action.Status.RUNNING).timestamp(java.lang.System.currentTimeMillis()).messages(List.of("proceeding message 1")) .build()); waitNextMillis(); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId) - .status(Action.Status.RUNNING).timestamp(System.currentTimeMillis()).messages(List.of("proceeding message 2")) + .status(Action.Status.RUNNING).timestamp(java.lang.System.currentTimeMillis()).messages(List.of("proceeding message 2")) .build()); final List messages = controllerManagement.getActionHistoryMessages(actionId, 2); @@ -242,7 +243,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest { assertThat(actionId1).isNotNull(); final ActionStatusCreateBuilder status = ActionStatusCreate.builder().actionId(actionId1).status(Status.WARNING); for (int i = 0; i < maxStatusEntries; i++) { - controllerManagement.addInformationalActionStatus(status.messages(List.of("Msg " + i)).timestamp(System.currentTimeMillis()).build()); + controllerManagement.addInformationalActionStatus(status.messages(List.of("Msg " + i)).timestamp(java.lang.System.currentTimeMillis()).build()); } final ActionStatusCreate actionStatusCreate = status.build(); assertThatExceptionOfType(AssignmentQuotaExceededException.class) @@ -254,7 +255,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest { assertThat(actionId2).isNotEqualTo(actionId1); final ActionStatusCreateBuilder statusWarning = ActionStatusCreate.builder().actionId(actionId2).status(Status.WARNING); for (int i = 0; i < maxStatusEntries; i++) { - controllerManagement.addUpdateActionStatus(statusWarning.messages(List.of("Msg " + i)).timestamp(System.currentTimeMillis()).build()); + controllerManagement.addUpdateActionStatus(statusWarning.messages(List.of("Msg " + i)).timestamp(java.lang.System.currentTimeMillis()).build()); } final ActionStatusCreate actionStatusCreateQE = statusWarning.build(); assertThatExceptionOfType(AssignmentQuotaExceededException.class) @@ -1461,7 +1462,6 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest { @Expect(type = SoftwareModuleUpdatedEvent.class, count = 3) } ) void assignVersionToTarget() { - final DistributionSet knownDistributionSet = testdataFactory.createDistributionSet(); // GIVEN @@ -1798,8 +1798,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest { } private void createTargetType(String targetTypeName) { - systemSecurityContext.runAsSystem( - () -> targetTypeManagement.create(TargetTypeManagement.Create.builder().name(targetTypeName).build())); + asSystem(() -> targetTypeManagement.create(TargetTypeManagement.Create.builder().name(targetTypeName).build())); } private void addAttributeAndVerify(final String controllerId) { @@ -1807,8 +1806,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest { testData.put("test1", "testdata1"); controllerManagement.updateControllerAttributes(controllerId, testData, null); - assertThat(targetManagement.getControllerAttributes(controllerId)).as("Controller Attributes are wrong") - .isEqualTo(testData); + assertThat(targetManagement.getControllerAttributes(controllerId)).as("Controller Attributes are wrong").isEqualTo(testData); } private void addSecondAttributeAndVerify(final String controllerId) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DeploymentManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DeploymentManagementTest.java index c257edc9a..13de6403e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DeploymentManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DeploymentManagementTest.java @@ -32,7 +32,7 @@ import jakarta.validation.ConstraintViolationException; import lombok.Getter; import org.assertj.core.api.Assertions; -import org.eclipse.hawkbit.repository.qfields.ActionStatusFields; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetTagManagement; import org.eclipse.hawkbit.repository.Identifiable; @@ -81,6 +81,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.qfields.ActionStatusFields; import org.eclipse.hawkbit.repository.test.matcher.Expect; import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; @@ -526,7 +527,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { assertThat(actionRepository.count()).isEqualTo(20); assertThat(findActionsByDistributionSet(PAGE, ds.getId())).as("Offline actions are not active") .allMatch(action -> !action.isActive()).as("Actions should be initiated by current user") - .allMatch(a -> a.getInitiatedBy().equals(tenantAware.getCurrentUsername())); + .allMatch(a -> a.getInitiatedBy().equals(AccessContext.actor())); assertThat(targetManagement.findByInstalledDistributionSet(ds.getId(), PAGE).getContent()) .usingElementComparator(controllerIdComparator()).containsAll(targets).hasSize(10) @@ -568,7 +569,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { // don't use peek since it is by documentation mainly for debugging and could be skipped in some cases assertThat(a.getInitiatedBy()) .as("Actions should be initiated by current user") - .isEqualTo(tenantAware.getCurrentUsername()); + .isEqualTo(AccessContext.actor()); return a; }) .map(action -> action.getDistributionSet().getId()).toList(); @@ -593,7 +594,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { @Expect(type = TenantConfigurationCreatedEvent.class, count = 1), @Expect(type = TenantConfigurationUpdatedEvent.class, count = 1) }) void assignDistributionSetAndAutoCloseActiveActions() { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, true); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, true); try { final List targets = testdataFactory.createTargets(10); @@ -615,7 +616,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { .as("InstallationDate not set").allMatch(target -> (target.getInstallationDate() == null)); } finally { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, false); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, false); } } @@ -672,7 +673,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final List deploymentRequests = createAssignmentRequests(distributionSets, targets, 34); enableMultiAssignments(); - final List results = deploymentManagement.assignDistributionSets(deploymentRequests); + final List results = deploymentManagement.assignDistributionSets(deploymentRequests, null); assertThat(getResultingActionCount(results)).isEqualTo(deploymentRequests.size()); final List dsIds = distributionSets.stream().map(DistributionSet::getId).toList(); @@ -682,7 +683,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { .map(a -> { // don't use peek since it is by documentation mainly for debugging and could be skipped in some cases assertThat(a.getInitiatedBy()).as("Initiated by current user") - .isEqualTo(tenantAware.getCurrentUsername()); + .isEqualTo(AccessContext.actor()); return a; }) .map(action -> action.getDistributionSet().getId()).toList(); @@ -712,7 +713,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final List deploymentRequests = createAssignmentRequests(distributionSets, targets, 34, false); enableMultiAssignments(); - final List results = deploymentManagement.assignDistributionSets(deploymentRequests); + final List results = deploymentManagement.assignDistributionSets(deploymentRequests, null); assertThat(getResultingActionCount(results)).isEqualTo(deploymentRequests.size()); @@ -721,7 +722,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).forEach(action -> { assertThat(action.getDistributionSet().getId()).isIn(dsIds); assertThat(action.getInitiatedBy()) - .as("Should be Initiated by current user").isEqualTo(tenantAware.getCurrentUsername()); + .as("Should be Initiated by current user").isEqualTo(AccessContext.actor()); deploymentManagement.cancelAction(action.getId()); })); } @@ -742,10 +743,10 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final List deploymentRequests = List.of(targetToDS0, targetToDS1); Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class) - .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests)); + .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests, null)); enableMultiAssignments(); - assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(Arrays.asList(targetToDS0, targetToDS1)))).isEqualTo(2); + assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(List.of(targetToDS0, targetToDS1), null))).isEqualTo(2); } /** @@ -793,7 +794,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { deploymentManagement.findActionsByTarget(controllerId, PAGE).forEach(action -> { assertThat(action.getDistributionSet().getId()).isIn(distributionSet.getId()); assertThat(action.getInitiatedBy()) - .as("Should be Initiated by current user").isEqualTo(tenantAware.getCurrentUsername()); + .as("Should be Initiated by current user").isEqualTo(AccessContext.actor()); if (confirmationRequired) { assertThat(action.getStatus()).isEqualTo(Status.WAIT_FOR_CONFIRMATION); } else { @@ -906,7 +907,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { deploymentManagement.findActionsByTarget(controllerId, PAGE).forEach(action -> { assertThat(action.getDistributionSet().getId()).isIn(distributionSet.getId()); assertThat(action.getInitiatedBy()) - .as("Should be Initiated by current user").isEqualTo(tenantAware.getCurrentUsername()); + .as("Should be Initiated by current user").isEqualTo(AccessContext.actor()); assertThat(action.getStatus()).isEqualTo(RUNNING); })); } @@ -930,13 +931,13 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final String targetId = testdataFactory.createTarget().getControllerId(); final Long dsId = testdataFactory.createDistributionSet().getId(); final List twoEqualAssignments = Collections.nCopies(2, DeploymentRequest.builder(targetId, dsId).build()); - assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignments))).isEqualTo(1); + assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignments, null))).isEqualTo(1); enableMultiAssignments(); final List twoEqualAssignmentsWithWeight = Collections.nCopies( 2, DeploymentRequest.builder(targetId, dsId).weight(555).build()); - assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignmentsWithWeight))).isEqualTo(1); + assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignmentsWithWeight, null))).isEqualTo(1); } /** @@ -965,7 +966,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { enableMultiAssignments(); Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class) - .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests)); + .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests, null)); assertThat(actionRepository.countByTargetControllerId(controllerId)).isZero(); } @@ -981,7 +982,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final DeploymentRequest assignWithWeight = DeploymentRequest.builder(targetId, dsId).weight(567).build(); enableMultiAssignments(); - assertThat(deploymentManagement.assignDistributionSets(List.of(assignWithoutWeight, assignWithWeight))).isNotNull(); + assertThat(deploymentManagement.assignDistributionSets(List.of(assignWithoutWeight, assignWithWeight), null)).isNotNull(); } /** @@ -993,7 +994,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final Long dsId = testdataFactory.createDistributionSet().getId(); final DeploymentRequest assignWithoutWeight = DeploymentRequest.builder(targetId, dsId).weight(456).build(); - assertThat(deploymentManagement.assignDistributionSets(Collections.singletonList(assignWithoutWeight))).isNotNull().size().isEqualTo(1); + assertThat(deploymentManagement.assignDistributionSets(Collections.singletonList(assignWithoutWeight), null)).isNotNull().size().isEqualTo(1); } /** @@ -1020,14 +1021,14 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { enableMultiAssignments(); final List deploymentRequestsTooLow = Collections.singletonList(weightTooLow); Assertions.assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequestsTooLow)); + .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequestsTooLow, null)); final List deploymentRequestsTooHigh = Collections.singletonList(weightTooHigh); Assertions.assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy( - () -> deploymentManagement.assignDistributionSets(deploymentRequestsTooHigh)); + () -> deploymentManagement.assignDistributionSets(deploymentRequestsTooHigh, null)); final Long validActionId1 = getFirstAssignedAction( - deploymentManagement.assignDistributionSets(Collections.singletonList(validRequest1)).get(0)).getId(); + deploymentManagement.assignDistributionSets(Collections.singletonList(validRequest1), null).get(0)).getId(); final Long validActionId2 = getFirstAssignedAction( - deploymentManagement.assignDistributionSets(Collections.singletonList(validRequest2)).get(0)).getId(); + deploymentManagement.assignDistributionSets(Collections.singletonList(validRequest2), null).get(0)).getId(); assertThat(actionRepository.findById(validActionId1).get().getWeight()).get().isEqualTo(Action.WEIGHT_MAX); assertThat(actionRepository.findById(validActionId2).get().getWeight()).get().isEqualTo(Action.WEIGHT_MIN); } @@ -1062,7 +1063,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final Page actions = actionRepository.findAll(PAGE); assertThat(actions.getNumberOfElements()).as("wrong size of actions").isEqualTo(20); assertThat(actions).as("Actions should be initiated by current user") - .allMatch(a -> a.getInitiatedBy().equals(tenantAware.getCurrentUsername())); + .allMatch(a -> a.getInitiatedBy().equals(AccessContext.actor())); final Iterable allFoundTargets = targetManagement.findAll(PAGE).getContent(); @@ -1161,7 +1162,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { // retrieving all Actions created by the assignDistributionSet call final Page page = actionRepository.findAll(PAGE); assertThat(page).as("Actions should be initiated by current user") - .allMatch(a -> a.getInitiatedBy().equals(tenantAware.getCurrentUsername())); + .allMatch(a -> a.getInitiatedBy().equals(AccessContext.actor())); // and verify the number assertThat(page.getTotalElements()).as("wrong size of actions") .isEqualTo(noOfDeployedTargets * noOfDistributionSets); @@ -1556,7 +1557,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { deploymentRequests.add(deployment); } - deploymentManagement.assignDistributionSets(deploymentRequests); + deploymentManagement.assignDistributionSets(deploymentRequests, null); implicitLock(ds); final List content = targetManagement.findAll(Pageable.unpaged()).getContent(); @@ -1579,7 +1580,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final DeploymentRequest deployment2 = DeploymentRequest.builder(target2.getControllerId(), ds.getId()).build(); final List deploymentRequests = Arrays.asList(deployment1, deployment2); - deploymentManagement.assignDistributionSets(deploymentRequests); + deploymentManagement.assignDistributionSets(deploymentRequests, null); implicitLock(ds); final DistributionSet assignedDsTarget1 = ((JpaTarget) targetManagement @@ -1605,7 +1606,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { final List deploymentRequests = List.of(deploymentRequest); assertThatExceptionOfType(IncompatibleTargetTypeException.class) - .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests)); + .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests, null)); } /** @@ -1621,7 +1622,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { .builder(targetWithEmptyType.getControllerId(), ds.getId()).build(); final List deploymentRequests = Collections.singletonList(deploymentRequestWithEmptyType); assertThatExceptionOfType(IncompatibleTargetTypeException.class) - .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests)); + .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests, null)); } @Test @@ -1648,7 +1649,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { () -> assignDistributionSet(exceededQuotaDsAssign.getId(), target.getControllerId())); // set purge config to 25 % - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE, 25); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE, 25); // assign again assignDistributionSet(exceededQuotaDsAssign.getId(), target.getControllerId()); @@ -1687,7 +1688,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { assertEquals(20, deploymentManagement.countActionsByTarget(target.getControllerId())); // set purge config to 25 % - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE, 25); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE, 25); rolloutHandler.handleAll(); assertEquals(16, deploymentManagement.countActionsByTarget(target.getControllerId())); @@ -1708,7 +1709,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { rolloutHandler.handleAll(); } - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE, 25); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE, 25); deploymentManagement.handleMaxAssignmentsExceeded(target.getId(), 5L, new AssignmentQuotaExceededException()); // only 3 actions should be deleted in such case : assertEquals(15, deploymentManagement.countActionsByTarget(target.getControllerId())); @@ -1753,7 +1754,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { private void assertDsExclusivelyAssignedToTargets(final List targets, final long dsId, final boolean active, final Status status) { final List assignment = findActionsByDistributionSet(PAGE, dsId).getContent(); - final String currentUsername = tenantAware.getCurrentUsername(); + final String currentUsername = AccessContext.actor(); assertThat(assignment).hasSize(10).allMatch(action -> action.isActive() == active) .as("Is assigned to DS " + dsId).allMatch(action -> action.getDistributionSet().getId().equals(dsId)) @@ -1771,7 +1772,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest { deploymentRequests.add(new DeploymentRequest(controllerId, distributionSet.getId(), ActionType.FORCED, 0, null, null, null, null, confirmationRequired)); } - return deploymentManagement.assignDistributionSets(deploymentRequests); + return deploymentManagement.assignDistributionSets(deploymentRequests, null); } private int getResultingActionCount(final List results) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DistributionSetInvalidationManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DistributionSetInvalidationManagementTest.java index 6a7ff2d7a..ee0883b2d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DistributionSetInvalidationManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DistributionSetInvalidationManagementTest.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.management; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import java.util.Collection; import java.util.Collections; @@ -185,11 +186,9 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe @Test @WithUser(authorities = { "READ_DISTRIBUTION_SET", "UPDATE_DISTRIBUTION_SET" }) void verifyInvalidateWithReadAndUpdateRepoAuthority() { - final InvalidationTestData invalidationTestData = systemSecurityContext - .runAsSystem(() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAuthority")); - + final InvalidationTestData invalidationTestData = asSystem(() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAuthority")); distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation( - Collections.singletonList(invalidationTestData.distributionSet().getId()), ActionCancellationType.NONE)); + List.of(invalidationTestData.distributionSet().getId()), ActionCancellationType.NONE)); assertThat(distributionSetRepository.findById(invalidationTestData.distributionSet().getId()).orElseThrow().isValid()).isFalse(); } @@ -199,7 +198,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe @Test @WithUser(authorities = { "READ_DISTRIBUTION_SET", "UPDATE_DISTRIBUTION_SET", "UPDATE_TARGET" }) void verifyInvalidateWithReadAndUpdateRepoAndUpdateTargetAuthority() { - final InvalidationTestData invalidationTestData = systemSecurityContext.runAsSystem( + final InvalidationTestData invalidationTestData = asSystem( () -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAndUpdateTargetAuthority")); final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation( @@ -219,7 +218,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe @Test @WithUser(authorities = { "READ_DISTRIBUTION_SET", "UPDATE_DISTRIBUTION_SET", "UPDATE_TARGET", "UPDATE_ROLLOUT" }) void verifyInvalidateWithReadAndUpdateRepoAndUpdateTargetAndUpdateRolloutAuthority() { - final InvalidationTestData invalidationTestData = systemSecurityContext.runAsSystem( + final InvalidationTestData invalidationTestData = asSystem( () -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAndUpdateTargetAuthority")); distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation( @@ -241,7 +240,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe // if implicitly locked - the old distribution set becomes stale distributionSet = assignDistributionSet(distributionSet, targets).getDistributionSet(); final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.create(TargetFilterQueryManagement.Create.builder() - .name(testName).query("name==*").autoAssignDistributionSet(distributionSet).build()); + .name(testName).query("name==*").autoAssignDistributionSet(distributionSet).build()); final Rollout rollout = testdataFactory.createRolloutByVariables(testName, "desc", 2, "name==*", distributionSet, "50", "80"); return new InvalidationTestData(distributionSet, targets, targetFilterQuery, rollout); @@ -260,9 +259,11 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe } private DistributionSetInvalidationCount countEntitiesForInvalidation(final DistributionSetInvalidation distributionSetInvalidation) { - return systemSecurityContext.runAsSystem(() -> { + return asSystem(() -> { final Collection setIds = distributionSetInvalidation.getDistributionSetIds(); - final long rolloutsCount = distributionSetInvalidation.getActionCancellationType() != ActionCancellationType.NONE ? countRolloutsForInvalidation(setIds) : 0; + final long rolloutsCount = distributionSetInvalidation.getActionCancellationType() != ActionCancellationType.NONE + ? countRolloutsForInvalidation(setIds) + : 0; final long autoAssignmentsCount = countAutoAssignmentsForInvalidation(setIds); final long actionsCount = countActionsForInvalidation(setIds, distributionSetInvalidation.getActionCancellationType()); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ManagementSecurityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ManagementSecurityTest.java index 01b8af205..1be9d7d40 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ManagementSecurityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ManagementSecurityTest.java @@ -38,8 +38,9 @@ import io.github.classgraph.ClassInfo; import io.github.classgraph.ScanResult; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions; +import org.eclipse.hawkbit.auth.SpringEvalExpressions; import org.eclipse.hawkbit.repository.PermissionSupport; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantStatsManagement; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; @@ -74,6 +75,8 @@ class ManagementSecurityTest extends AbstractJpaIntegrationTest { @Autowired protected TenantStatsManagement tenantStatsManagement; + @Autowired + protected TenantConfigurationManagement tenantConfigurationManagement; @Override @BeforeEach @@ -86,19 +89,21 @@ class ManagementSecurityTest extends AbstractJpaIntegrationTest { void testMethod(final Class managementInterface, final Method managementInterfaceMethod) { final Object managementObject = TenantStatsManagement.class == managementInterface ? tenantStatsManagement // it's not a field of AbstractIntegrationTest, so we need to use the autowired instance - : Stream - .of(AbstractIntegrationTest.class.getDeclaredFields()) - .filter(field -> managementInterface.isAssignableFrom(field.getType())) - .findFirst() - .map(field -> { - field.setAccessible(true); - try { - return field.get(this); - } catch (final IllegalAccessException e) { - throw new AssertionError("Could not access field " + field.getName(), e); - } - }) - .orElseThrow(() -> new AssertionError("No management implementation found for " + managementInterface)); + : TenantConfigurationManagement.class == managementInterface + ? tenantConfigurationManagement // it's not a field of AbstractIntegrationTest, so we need to use the autowired instance + : Stream + .of(AbstractIntegrationTest.class.getDeclaredFields()) + .filter(field -> managementInterface.isAssignableFrom(field.getType())) + .findFirst() + .map(field -> { + field.setAccessible(true); + try { + return field.get(this); + } catch (final IllegalAccessException e) { + throw new AssertionError("Could not access field " + field.getName(), e); + } + }) + .orElseThrow(() -> new AssertionError("No management implementation found for " + managementInterface)); final Class managedClass = ClassUtils.getUserClass(managementObject); // managed class is a proxy final Method implementationMethod = findImplementationMethod(managedClass, managementInterfaceMethod); if (implementationMethod == null) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementFlowTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementFlowTest.java index bf2bf0da2..f08969708 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementFlowTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementFlowTest.java @@ -27,11 +27,8 @@ import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; -import org.eclipse.hawkbit.security.SecurityContextSerializer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.test.context.TestPropertySource; @@ -45,15 +42,6 @@ import org.springframework.test.context.TestPropertySource; @TestPropertySource(properties = { "hawkbit.server.repository.dynamicRolloutsMinInvolvePeriodMS=-1" }) class RolloutManagementFlowTest extends AbstractJpaIntegrationTest { - @Configuration - static class Config { - - @Bean - SecurityContextSerializer securityContextSerializer() { - return SecurityContextSerializer.JSON_SERIALIZATION; - } - } - @BeforeEach void reset() { this.approvalStrategy.setApprovalNeeded(false); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementTest.java index 984d11785..817220b30 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementTest.java @@ -27,8 +27,8 @@ import jakarta.validation.ValidationException; import org.assertj.core.api.Assertions; import org.assertj.core.api.Condition; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.RolloutManagement.Create; @@ -243,8 +243,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest { */ @Test void rolloutAssignsNewDistributionSetAndAutoCloseActiveActions() { - tenantConfigurationManagement - .addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, true); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, true); try { // manually assign distribution set to target @@ -277,8 +276,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest { .filter(action -> !action.getId().equals(manuallyAssignedActionId)).findAny().get(); assertThat(rolloutCreatedAction.getStatus()).isEqualTo(Status.RUNNING); } finally { - tenantConfigurationManagement - .addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, false); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, false); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/SoftwareModuleManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/SoftwareModuleManagementTest.java index cffa35690..8f0fd97cf 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/SoftwareModuleManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/SoftwareModuleManagementTest.java @@ -25,6 +25,7 @@ import java.util.Set; import jakarta.validation.ConstraintViolationException; import org.eclipse.hawkbit.artifact.exception.ArtifactBinaryNotFoundException; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SoftwareModuleManagement.Create; @@ -481,13 +482,13 @@ class SoftwareModuleManagementTest assertThat(artifactRepository.findAll()).hasSize(results.length); for (final Artifact result : results) { assertThat(result.getId()).isNotNull(); - assertThat(artifactStorage.getBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash())).isNotNull(); + assertThat(artifactStorage.getBySha1(AccessContext.tenant(), result.getSha1Hash())).isNotNull(); } } private void assertArtifactDoesntExist(final Artifact... results) { for (final Artifact result : results) { - final String currentTenant = tenantAware.getCurrentTenant(); + final String currentTenant = AccessContext.tenant(); final String sha1Hash = result.getSha1Hash(); assertThatExceptionOfType(ArtifactBinaryNotFoundException.class) .isThrownBy(() -> artifactStorage.getBySha1(currentTenant, sha1Hash)); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/SystemManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/SystemManagementTest.java index 4a4e8695f..168694e1a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/SystemManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/SystemManagementTest.java @@ -14,13 +14,12 @@ import static org.assertj.core.api.Assertions.assertThat; import java.io.ByteArrayInputStream; import java.util.List; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.model.ArtifactUpload; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.report.TenantUsage; import org.eclipse.hawkbit.repository.test.util.DisposableSqlTestDatabaseExtension; import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch; import org.junit.jupiter.api.Test; @@ -45,89 +44,6 @@ class SystemManagementTest extends AbstractJpaIntegrationTest { assertThat(systemManagement.findTenants(PAGE).getContent()).hasSize(3); } - /** - * Ensures that getSystemUsageStatisticsWithTenants returns the usage of all tenants and not only the first 1000 (max page size). - */ - @Test - void systemUsageReportCollectsStatisticsOfManyTenants() { - // Prepare tenants - createTestTenantsForSystemStatistics(1050, 0, 0, 0); - - final List tenants = systemManagement.getSystemUsageStatisticsWithTenants().getTenants(); - assertThat(tenants).hasSize(1051); // +1 from the setup - } - - /** - * Checks that the system report calculates correctly the artifact size of all tenants in the system. It ignores deleted software modules with their artifacts. - */ - @Test - void systemUsageReportCollectsArtifactsOfAllTenants() { - // Prepare tenants - createTestTenantsForSystemStatistics(2, 1234, 0, 0); - - // overall data - assertThat(systemManagement.getSystemUsageStatistics().getOverallArtifacts()).isEqualTo(2); - assertThat(systemManagement.getSystemUsageStatistics().getOverallArtifactVolumeInBytes()).isEqualTo(1234 * 2); - - // per tenant data - final List tenants = systemManagement.getSystemUsageStatisticsWithTenants().getTenants(); - assertThat(tenants).hasSize(3); - final TenantUsage tenantUsage0 = new TenantUsage("TENANT0"); - tenantUsage0.setArtifacts(1); - tenantUsage0.setOverallArtifactVolumeInBytes(1234); - final TenantUsage tenantUsage1 = new TenantUsage("TENANT1"); - tenantUsage1.setArtifacts(1); - tenantUsage1.setOverallArtifactVolumeInBytes(1234); - assertThat(tenants).containsOnly(new TenantUsage("DEFAULT"), - tenantUsage0, - tenantUsage1); - } - - /** - * Checks that the system report calculates correctly the targets size of all tenants in the system - */ - @Test - void systemUsageReportCollectsTargetsOfAllTenants() { - // Prepare tenants - createTestTenantsForSystemStatistics(2, 0, 100, 0); - - // overall data - assertThat(systemManagement.getSystemUsageStatistics().getOverallTargets()).isEqualTo(200); - assertThat(systemManagement.getSystemUsageStatistics().getOverallActions()).isZero(); - - // per tenant data - final List tenants = systemManagement.getSystemUsageStatisticsWithTenants().getTenants(); - assertThat(tenants).hasSize(3); - final TenantUsage tenantUsage0 = new TenantUsage("TENANT0"); - tenantUsage0.setTargets(100); - final TenantUsage tenantUsage1 = new TenantUsage("TENANT1"); - tenantUsage1.setTargets(100); - assertThat(tenants).containsOnly(new TenantUsage("DEFAULT"), tenantUsage0, tenantUsage1); - } - - /** - * Checks that the system report calculates correctly the actions size of all tenants in the system - */ - @Test - void systemUsageReportCollectsActionsOfAllTenants() { - // Prepare tenants - createTestTenantsForSystemStatistics(2, 0, 20, 2); - - // 2 tenants, 100 targets each, 2 deployments per target => 400 - assertThat(systemManagement.getSystemUsageStatistics().getOverallActions()).isEqualTo(80); - - // per tenant data - final List tenants = systemManagement.getSystemUsageStatisticsWithTenants().getTenants(); - assertThat(tenants).hasSize(3); - final TenantUsage tenantUsage0 = new TenantUsage("TENANT0"); - tenantUsage0.setTargets(20); - tenantUsage0.setActions(40); - final TenantUsage tenantUsage1 = new TenantUsage("TENANT1"); - tenantUsage1.setTargets(20); - tenantUsage1.setActions(40); - assertThat(tenants).containsOnly(new TenantUsage("DEFAULT"), tenantUsage0, tenantUsage1); - } - private void createTestTenantsForSystemStatistics(final int tenants, final int artifactSize, final int targets, final int updates) { final byte[] random = new byte[artifactSize]; RND.nextBytes(random); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetFilterQueryManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetFilterQueryManagementTest.java index ba73a1d0f..968035427 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetFilterQueryManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetFilterQueryManagementTest.java @@ -20,7 +20,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.function.Supplier; import jakarta.validation.ConstraintViolationException; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetManagementTest.java index e6fe687d5..5568031fd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetManagementTest.java @@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.management; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.fail; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import java.net.URI; import java.util.ArrayList; @@ -31,8 +32,8 @@ import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.SetJoin; import jakarta.validation.ConstraintViolationException; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.SpRole; +import org.eclipse.hawkbit.auth.SpPermission; +import org.eclipse.hawkbit.auth.SpRole; import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.repository.MetadataSupport; import org.eclipse.hawkbit.repository.TargetManagement.Create; @@ -145,7 +146,7 @@ class TargetManagementTest extends AbstractRepositoryManagementWithMetadataTest< createdTarget::getSecurityToken); // retrieve security token as system code execution - final String securityTokenAsSystemCode = systemSecurityContext.runAsSystem(createdTarget::getSecurityToken); + final String securityToken = asSystem(createdTarget::getSecurityToken); // retrieve security token without any permissions final String securityTokenWithoutPermission = SecurityContextSwitch @@ -155,7 +156,7 @@ class TargetManagementTest extends AbstractRepositoryManagementWithMetadataTest< assertThat(securityTokenWithReadPermission).isNotNull(); assertThat(securityTokenWithTargetAdminPermission).isNotNull(); assertThat(securityTokenWithTenantAdminPermission).isNotNull(); - assertThat(securityTokenAsSystemCode).isNotNull(); + assertThat(securityToken).isNotNull(); assertThat(securityTokenWithoutPermission).isNull(); } @@ -216,7 +217,7 @@ class TargetManagementTest extends AbstractRepositoryManagementWithMetadataTest< createTargetWithAttributes("4711"); - final long current = System.currentTimeMillis(); + final long current = java.lang.System.currentTimeMillis(); controllerManagement.findOrRegisterTargetIfItDoesNotExist("4711", LOCALHOST); final DistributionSetAssignmentResult result = assignDistributionSet(testDs1.getId(), "4711"); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TenantConfigurationManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TenantConfigurationManagementTest.java index 9040c0816..291a01357 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TenantConfigurationManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TenantConfigurationManagementTest.java @@ -31,7 +31,7 @@ import org.springframework.core.env.Environment; /** * Feature: Component Tests - Repository
- * Story: Tenant Configuration Management + * Story: AccessContext Configuration Management */ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest implements EnvironmentAware { @@ -51,7 +51,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple assertThat(envPropertyDefault).isNotNull(); // get the configuration from the system management - final TenantConfigurationValue defaultConfigValue = tenantConfigurationManagement.getConfigurationValue( + final TenantConfigurationValue defaultConfigValue = tenantConfigurationManagement().getConfigurationValue( TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class); assertThat(defaultConfigValue.isGlobal()).isTrue(); @@ -60,11 +60,11 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple // update the tenant specific configuration, create final String newConfigurationValue = "thisIsAnotherTokenName"; assertThat(newConfigurationValue).isNotEqualTo(defaultConfigValue.getValue()); - tenantConfigurationManagement.addOrUpdateConfiguration( + tenantConfigurationManagement().addOrUpdateConfiguration( TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, newConfigurationValue); // verify that new configuration value is used - final TenantConfigurationValue updatedConfigurationValue = tenantConfigurationManagement + final TenantConfigurationValue updatedConfigurationValue = tenantConfigurationManagement() .getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class); assertThat(updatedConfigurationValue.isGlobal()).isFalse(); @@ -73,16 +73,16 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple // update the tenant specific configuration, create final String newConfigurationValue2 = "thisIsAnotherTokenName2"; assertThat(newConfigurationValue2).isNotEqualTo(updatedConfigurationValue.getValue()); - tenantConfigurationManagement.addOrUpdateConfiguration( + tenantConfigurationManagement().addOrUpdateConfiguration( TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, newConfigurationValue2); // verify that new configuration value is used - final TenantConfigurationValue updatedConfigurationValue2 = tenantConfigurationManagement + final TenantConfigurationValue updatedConfigurationValue2 = tenantConfigurationManagement() .getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class); assertThat(updatedConfigurationValue2.isGlobal()).isFalse(); assertThat(updatedConfigurationValue2.getValue()).isEqualTo(newConfigurationValue2); - // assertThat(tenantConfigurationManagement.getTenantConfigurations()).hasSize(1); + // assertThat(tenantConfigurationManagement().getTenantConfigurations()).hasSize(1); } /** @@ -95,12 +95,12 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple final String value2 = "secondValue"; // add value first - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value1); - assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue()).isEqualTo(value1); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, value1); + assertThat(tenantConfigurationManagement().getConfigurationValue(configKey, String.class).getValue()).isEqualTo(value1); // update to value second - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value2); - assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue()).isEqualTo(value2); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, value2); + assertThat(tenantConfigurationManagement().getConfigurationValue(configKey, String.class).getValue()).isEqualTo(value2); } /** @@ -114,12 +114,12 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple }}; // add value first - tenantConfigurationManagement.addOrUpdateConfiguration(configuration); - assertThat(tenantConfigurationManagement.getConfigurationValue( + tenantConfigurationManagement().addOrUpdateConfiguration(configuration); + assertThat(tenantConfigurationManagement().getConfigurationValue( TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue()) .isEqualTo("token_123"); assertThat( - tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue()) + tenantConfigurationManagement().getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue()) .isTrue(); } @@ -130,11 +130,11 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple void storeAndUpdateTenantSpecificConfigurationAsBoolean() { final String configKey = TenantConfigurationKey.AUTHENTICATION_HEADER_ENABLED; final Boolean value1 = true; - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value1); - assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, Boolean.class).getValue()).isEqualTo(value1); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, value1); + assertThat(tenantConfigurationManagement().getConfigurationValue(configKey, Boolean.class).getValue()).isEqualTo(value1); final Boolean value2 = false; - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value2); - assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, Boolean.class).getValue()).isEqualTo(value2); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, value2); + assertThat(tenantConfigurationManagement().getConfigurationValue(configKey, Boolean.class).getValue()).isEqualTo(value2); } /** @@ -146,7 +146,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple final String value1 = "thisIsNotABoolean"; // add value as String - assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value1)) + assertThatThrownBy(() -> tenantConfigurationManagement().addOrUpdateConfiguration(configKey, value1)) .as("Should not have worked as value is not a boolean") .isInstanceOf(TenantConfigurationValidatorException.class); } @@ -163,15 +163,15 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple }}; try { - tenantConfigurationManagement.addOrUpdateConfiguration(configuration); + tenantConfigurationManagement().addOrUpdateConfiguration(configuration); fail("should not have worked as type is wrong"); } catch (final TenantConfigurationValidatorException e) { assertThat( - tenantConfigurationManagement.getConfigurationValue( + tenantConfigurationManagement().getConfigurationValue( TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue()) .isNotEqualTo("token_123"); assertThat( - tenantConfigurationManagement.getConfigurationValue( + tenantConfigurationManagement().getConfigurationValue( TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue()) .isNotEqualTo(true); } @@ -185,22 +185,22 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple final String configKey = TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY; // gateway token does not have default value so no configuration value should be available - final String defaultConfigValue = tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue(); + final String defaultConfigValue = tenantConfigurationManagement().getConfigurationValue(configKey, String.class).getValue(); assertThat(defaultConfigValue).isEmpty(); // update the tenant specific configuration final String newConfigurationValue = "thisIsAnotherValueForPolling"; assertThat(newConfigurationValue).isNotEqualTo(defaultConfigValue); - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, newConfigurationValue); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, newConfigurationValue); // verify that new configuration value is used - final String updatedConfigurationValue = tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue(); + final String updatedConfigurationValue = tenantConfigurationManagement().getConfigurationValue(configKey, String.class).getValue(); assertThat(updatedConfigurationValue).isEqualTo(newConfigurationValue); // delete the tenant specific configuration - tenantConfigurationManagement.deleteConfiguration(configKey); + tenantConfigurationManagement().deleteConfiguration(configKey); // ensure that now gateway token is set again, because is deleted and must be empty now - assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue()).isEmpty(); + assertThat(tenantConfigurationManagement().getConfigurationValue(configKey, String.class).getValue()).isEmpty(); } /** @@ -210,7 +210,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple void storesIntegerWhenStringIsExpected() { final String configKey = TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY; final Integer wrongDatType = 123; - assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDatType)) + assertThatThrownBy(() -> tenantConfigurationManagement().addOrUpdateConfiguration(configKey, wrongDatType)) .as("Should not have worked as integer is not a string") .isInstanceOf(TenantConfigurationValidatorException.class); } @@ -222,7 +222,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple void storesIntegerWhenBooleanIsExpected() { final String configKey = TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED; final Integer wrongDataType = 123; - assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataType)) + assertThatThrownBy(() -> tenantConfigurationManagement().addOrUpdateConfiguration(configKey, wrongDataType)) .as("Should not have worked as integer is not a boolean") .isInstanceOf(TenantConfigurationValidatorException.class); } @@ -234,7 +234,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple void storesIntegerWhenPollingIntervalIsExpected() { final String configKey = TenantConfigurationKey.POLLING_TIME; final Integer wrongDataType = 123; - assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataType)) + assertThatThrownBy(() -> tenantConfigurationManagement().addOrUpdateConfiguration(configKey, wrongDataType)) .as("Should not have worked as integer is not a time field") .isInstanceOf(TenantConfigurationValidatorException.class); } @@ -246,7 +246,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple void storesWrongFormattedStringAsPollingInterval() { final String configKey = TenantConfigurationKey.POLLING_TIME; final String wrongFormatted = "wrongFormatted"; - assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongFormatted)) + assertThatThrownBy(() -> tenantConfigurationManagement().addOrUpdateConfiguration(configKey, wrongFormatted)) .as("should not have worked as string is not a time field") .isInstanceOf(TenantConfigurationValidatorException.class); } @@ -259,7 +259,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple final String configKey = TenantConfigurationKey.POLLING_TIME; final String tooSmallDuration = DurationHelper.toString(getDurationByTimeValues(0, 0, 1)); - assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, tooSmallDuration)) + assertThatThrownBy(() -> tenantConfigurationManagement().addOrUpdateConfiguration(configKey, tooSmallDuration)) .as("Should not have worked as string has an invalid format") .isInstanceOf(TenantConfigurationValidatorException.class); } @@ -274,9 +274,9 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple final Duration duration = getDurationByTimeValues(1, 2, 0); assertThat(duration).isEqualTo(Duration.ofHours(1).plusMinutes(2)); - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, DurationHelper.toString(duration)); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, DurationHelper.toString(duration)); - final String storedDurationString = tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue(); + final String storedDurationString = tenantConfigurationManagement().getConfigurationValue(configKey, String.class).getValue(); assertThat(duration).isEqualTo(DurationHelper.fromString(storedDurationString)); } @@ -285,7 +285,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple */ @Test void requestConfigValueWithWrongType() { - assertThatThrownBy(() -> tenantConfigurationManagement.getConfigurationValue( + assertThatThrownBy(() -> tenantConfigurationManagement().getConfigurationValue( TenantConfigurationKey.POLLING_TIME, Serializable.class)) .isInstanceOf(TenantConfigurationValidatorException.class); } @@ -314,12 +314,12 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple } /** - * Tenant configuration which is not declared throws exception + * AccessContext configuration which is not declared throws exception */ @Test void storeTenantConfigurationWhichIsNotDeclaredThrowsException() { final String configKeyWhichDoesNotExists = "configKeyWhichDoesNotExists"; - assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKeyWhichDoesNotExists, "value")) + assertThatThrownBy(() -> tenantConfigurationManagement().addOrUpdateConfiguration(configKeyWhichDoesNotExists, "value")) .as("Expected InvalidTenantConfigurationKeyException for tenant configuration key which is not declared") .isInstanceOf(InvalidTenantConfigurationKeyException.class); } @@ -328,16 +328,16 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple void storeTenantConfigNumberValue() { final String configKey = TenantConfigurationKey.ACTION_CLEANUP_AUTO_EXPIRY; // set auto cleanup for 1 day in Integer ms - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, 86400000); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, 86400000); // expect long - Long autoCleanupDaysInMs = tenantConfigurationManagement.getConfigurationValue(configKey, Long.class).getValue(); + Long autoCleanupDaysInMs = tenantConfigurationManagement().getConfigurationValue(configKey, Long.class).getValue(); Assertions.assertEquals(86400000, autoCleanupDaysInMs); - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, 86400000); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, 86400000); // 30 days 2,592,000,000 ms as Long - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, 2592000000L); - autoCleanupDaysInMs = tenantConfigurationManagement.getConfigurationValue(configKey, Long.class).getValue(); + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, 2592000000L); + autoCleanupDaysInMs = tenantConfigurationManagement().getConfigurationValue(configKey, Long.class).getValue(); Assertions.assertEquals(2592000000L, autoCleanupDaysInMs); } @@ -346,7 +346,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple final String configKey = TenantConfigurationKey.ACTION_CLEANUP_AUTO_EXPIRY; // set auto cleanup for 1 day in String ms assertThatThrownBy(() -> - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, "86400000")) + tenantConfigurationManagement().addOrUpdateConfiguration(configKey, "86400000")) .as("Cannot convert the value 86400000 of type String to the type Long defined by the configuration key.") .isInstanceOf(TenantConfigurationValidatorException.class); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignExecutorIntTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignExecutorIntTest.java index 5f9abd12e..6c323e58a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignExecutorIntTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignExecutorIntTest.java @@ -64,9 +64,7 @@ class AutoAssignExecutorIntTest extends AbstractJpaIntegrationTest { */ @Test void autoAssignDistributionSetAndAutoCloseOldActions() { - - tenantConfigurationManagement - .addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, true); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, true); try { final String knownControllerId = "controller12345"; @@ -100,8 +98,7 @@ class AutoAssignExecutorIntTest extends AbstractJpaIntegrationTest { assertThat(rolloutCreatedAction.getStatus()).isEqualTo(Status.RUNNING); assertThat(rolloutCreatedAction.getActionType()).isEqualTo(ActionType.FORCED); } finally { - tenantConfigurationManagement - .addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, false); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, false); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignExecutorTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignExecutorTest.java index b170ca307..eb2f430cd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignExecutorTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/scheduler/AutoAssignExecutorTest.java @@ -10,8 +10,6 @@ package org.eclipse.hawkbit.repository.jpa.scheduler; 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; @@ -22,7 +20,6 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; -import org.eclipse.hawkbit.ContextAware; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetManagement; @@ -55,15 +52,13 @@ class AutoAssignExecutorTest { private DeploymentManagement deploymentManagement; @Mock private PlatformTransactionManager transactionManager; - @Mock - private ContextAware contextAware; private JpaAutoAssignExecutor autoAssignChecker; @BeforeEach void before() { autoAssignChecker = new JpaAutoAssignExecutor( - targetFilterQueryManagement, targetManagement, deploymentManagement, transactionManager, contextAware); + targetFilterQueryManagement, targetManagement, deploymentManagement, transactionManager); } /** @@ -71,7 +66,6 @@ class AutoAssignExecutorTest { */ @Test void checkForDevice() { - mockRunningAsNonSystem(); final String target = getRandomString(); final long ds = getRandomLong(); final TargetFilterQuery matching = mockFilterQuery(ds); @@ -83,8 +77,7 @@ class AutoAssignExecutorTest { autoAssignChecker.checkSingleTarget(target); - verify(deploymentManagement).assignDistributionSets( - eq(matching.getAutoAssignInitiatedBy()), Mockito.argThat(deployReqMatcher(target, ds)), any()); + verify(deploymentManagement).assignDistributionSets(Mockito.argThat(deployReqMatcher(target, ds)), any()); Mockito.verifyNoMoreInteractions(deploymentManagement); } @@ -113,12 +106,4 @@ class AutoAssignExecutorTest { return requests.size() == 1 && request.getDistributionSetId() == ds && request.getControllerId() == target; }; } - - private void mockRunningAsNonSystem() { - when(contextAware.getCurrentTenant()).thenReturn(getRandomString()); - 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-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java index 8b4eea05e..28ad17602 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java @@ -112,7 +112,7 @@ class MultiTenancyEntityTest extends AbstractJpaIntegrationTest { // logged in tenant mytenant - check if tenant default data is // autogenerated assertThat(distributionSetTypeManagement.findAll(PAGE)).isEmpty(); - SecurityContextSwitch.callAsPrivileged(() -> + SecurityContextSwitch.asPrivileged(() -> assertThat(systemManagement.createTenantMetadata("mytenant").getTenant().toUpperCase()).isEqualTo("mytenant".toUpperCase())); assertThat(distributionSetTypeManagement.findAll(PAGE)).isNotEmpty(); diff --git a/hawkbit-repository/hawkbit-repository-test/pom.xml b/hawkbit-repository/hawkbit-repository-test/pom.xml index df3c6e83f..9d92219fe 100644 --- a/hawkbit-repository/hawkbit-repository-test/pom.xml +++ b/hawkbit-repository/hawkbit-repository-test/pom.xml @@ -26,11 +26,6 @@ - - org.eclipse.hawkbit - hawkbit-security-core - ${project.version} - org.eclipse.hawkbit hawkbit-artifact-fs diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java index fbcf69616..1620eb63f 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java @@ -9,44 +9,32 @@ */ package org.eclipse.hawkbit.repository.test; -import java.util.Collections; import java.util.Locale; +import java.util.Optional; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicLong; -import org.eclipse.hawkbit.ContextAware; import org.eclipse.hawkbit.artifact.ArtifactStorage; import org.eclipse.hawkbit.artifact.fs.FileArtifactProperties; import org.eclipse.hawkbit.artifact.fs.FileArtifactStorage; import org.eclipse.hawkbit.artifact.urlresolver.PropertyBasedArtifactUrlResolver; import org.eclipse.hawkbit.artifact.urlresolver.PropertyBasedArtifactUrlResolverProperties; -import org.eclipse.hawkbit.im.authentication.Hierarchy; +import org.eclipse.hawkbit.auth.Hierarchy; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.RepositoryConfiguration; import org.eclipse.hawkbit.repository.RolloutApprovalStrategy; -import org.eclipse.hawkbit.repository.RolloutStatusCache; import org.eclipse.hawkbit.repository.event.ApplicationEventFilter; import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver; import org.eclipse.hawkbit.repository.test.util.RolloutTestApprovalStrategy; import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch; -import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.security.SecurityContextSerializer; -import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.security.SecurityTokenGenerator; -import org.eclipse.hawkbit.security.SpringSecurityAuditorAware; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.TenantAware.DefaultTenantResolver; -import org.eclipse.hawkbit.tenancy.TenantAware.TenantResolver; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; import org.eclipse.hawkbit.tenancy.configuration.ControllerPollProperties; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationEvent; @@ -71,7 +59,7 @@ import org.springframework.security.concurrent.DelegatingSecurityContextSchedule */ @Configuration @EnableConfigurationProperties({ - DdiSecurityProperties.class, PropertyBasedArtifactUrlResolverProperties.class, FileArtifactProperties.class, + PropertyBasedArtifactUrlResolverProperties.class, FileArtifactProperties.class, HawkbitSecurityProperties.class, ControllerPollProperties.class, TenantConfigurationProperties.class }) @Profile("test") @EnableAutoConfiguration @@ -82,6 +70,10 @@ public class TestConfiguration implements AsyncConfigurer { @Import(RepositoryConfiguration.class) static class OverridePropertiesSourceFromRepositoryConfiguration {} + static { + Hierarchy.setRoleHierarchy(RoleHierarchyImpl.fromHierarchy(Hierarchy.DEFAULT)); + } + @Override public Executor getAsyncExecutor() { return asyncExecutor(); @@ -103,29 +95,11 @@ public class TestConfiguration implements AsyncConfigurer { })); } - /** - * Disables caching during test to avoid concurrency failures during test. - */ - @Bean - RolloutStatusCache rolloutStatusCache(final TenantAware tenantAware) { - return new RolloutStatusCache(tenantAware); - } - @Bean LockRegistry lockRegistry() { return new DefaultLockRegistry(); } - @Bean - SecurityTokenGenerator securityTokenGenerator() { - return new SecurityTokenGenerator(); - } - - @Bean - SystemSecurityContext systemSecurityContext(final TenantAware tenantAware) { - return new SystemSecurityContext(tenantAware, RoleHierarchyImpl.fromHierarchy(Hierarchy.DEFAULT)); - } - @Bean ArtifactStorage artifactStorage(final FileArtifactProperties artifactFilesystemProperties) { return new FileArtifactStorage(artifactFilesystemProperties); @@ -143,25 +117,6 @@ public class TestConfiguration implements AsyncConfigurer { return new PropertyBasedArtifactUrlResolver(urlHandlerProperties, ""); } - @Bean - UserAuthoritiesResolver authoritiesResolver() { - return username -> Collections.emptyList(); - } - - @Bean - TenantResolver tenantResolver() { - return new DefaultTenantResolver(); - } - - @Bean - ContextAware contextAware( - final UserAuthoritiesResolver authoritiesResolver, - @Autowired(required = false) final SecurityContextSerializer securityContextSerializer, - final TenantResolver tenantResolver) { - // allow spying the security context - return org.mockito.Mockito.spy(new SecurityContextTenantAware(authoritiesResolver, securityContextSerializer, tenantResolver)); - } - @Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME) SimpleApplicationEventMulticaster applicationEventMulticaster(final ApplicationEventFilter applicationEventFilter) { final SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = @@ -182,7 +137,7 @@ public class TestConfiguration implements AsyncConfigurer { @Bean AuditorAware auditorAware() { - return new SpringSecurityAuditorAware(); + return () -> Optional.ofNullable(AccessContext.actor()); } @Bean diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java index 8914c94cb..122bdc7d6 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java @@ -10,9 +10,9 @@ package org.eclipse.hawkbit.repository.test.util; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_TENANT_CONFIGURATION; -import static org.eclipse.hawkbit.im.authentication.SpRole.CONTROLLER_ROLE; -import static org.eclipse.hawkbit.im.authentication.SpRole.SYSTEM_ROLE; +import static org.eclipse.hawkbit.auth.SpPermission.READ_TENANT_CONFIGURATION; +import static org.eclipse.hawkbit.auth.SpRole.CONTROLLER_ROLE; +import static org.eclipse.hawkbit.auth.SpRole.SYSTEM_ROLE; import java.io.File; import java.io.IOException; @@ -59,6 +59,7 @@ import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.helper.TenantConfigHelper; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate; import org.eclipse.hawkbit.repository.model.Action.ActionType; @@ -77,8 +78,6 @@ import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.test.TestConfiguration; import org.eclipse.hawkbit.repository.test.matcher.EventVerifier; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; @@ -164,20 +163,14 @@ public abstract class AbstractIntegrationTest { @Autowired protected ArtifactManagement artifactManagement; @Autowired - protected TenantAware tenantAware; - @Autowired protected SystemManagement systemManagement; @Autowired - protected TenantConfigurationManagement tenantConfigurationManagement; - @Autowired protected RolloutManagement rolloutManagement; @Autowired protected RolloutHandler rolloutHandler; @Autowired protected RolloutGroupManagement rolloutGroupManagement; @Autowired - protected SystemSecurityContext systemSecurityContext; - @Autowired protected ArtifactStorage artifactStorage; @Autowired protected QuotaManagement quotaManagement; @@ -215,21 +208,21 @@ public abstract class AbstractIntegrationTest { final String description = "Updated description."; osType = SecurityContextSwitch - .callAsPrivileged(() -> testdataFactory.findOrCreateSoftwareModuleType(TestdataFactory.SM_TYPE_OS)); - osType = SecurityContextSwitch.callAsPrivileged(() -> softwareModuleTypeManagement + .asPrivileged(() -> testdataFactory.findOrCreateSoftwareModuleType(TestdataFactory.SM_TYPE_OS)); + osType = SecurityContextSwitch.asPrivileged(() -> softwareModuleTypeManagement .update(SoftwareModuleTypeManagement.Update.builder().id(osType.getId()).description(description).build())); - appType = SecurityContextSwitch.callAsPrivileged( + appType = SecurityContextSwitch.asPrivileged( () -> testdataFactory.findOrCreateSoftwareModuleType(TestdataFactory.SM_TYPE_APP, Integer.MAX_VALUE)); - appType = SecurityContextSwitch.callAsPrivileged(() -> softwareModuleTypeManagement + appType = SecurityContextSwitch.asPrivileged(() -> softwareModuleTypeManagement .update(SoftwareModuleTypeManagement.Update.builder().id(appType.getId()).description(description).build())); runtimeType = SecurityContextSwitch - .callAsPrivileged(() -> testdataFactory.findOrCreateSoftwareModuleType(TestdataFactory.SM_TYPE_RT)); - runtimeType = SecurityContextSwitch.callAsPrivileged(() -> softwareModuleTypeManagement + .asPrivileged(() -> testdataFactory.findOrCreateSoftwareModuleType(TestdataFactory.SM_TYPE_RT)); + runtimeType = SecurityContextSwitch.asPrivileged(() -> softwareModuleTypeManagement .update(SoftwareModuleTypeManagement.Update.builder().id(runtimeType.getId()).description(description).build())); - standardDsType = SecurityContextSwitch.callAsPrivileged(() -> testdataFactory.findOrCreateDefaultTestDsType()); + standardDsType = SecurityContextSwitch.asPrivileged(() -> testdataFactory.findOrCreateDefaultTestDsType()); // publish the reset counter market event to reset the counters after // setup. The setup is transparent by the test and its @ExpectedEvent @@ -238,7 +231,6 @@ public abstract class AbstractIntegrationTest { // ApplicationEventMultiCaster which the TestConfiguration is doing so // the order of the events keep the same. EventVerifier.publishResetMarkerEvent(eventPublisher); - } @AfterEach @@ -252,6 +244,10 @@ public abstract class AbstractIntegrationTest { } } + protected static TenantConfigurationManagement tenantConfigurationManagement() { + return TenantConfigHelper.getTenantConfigurationManagement(); + } + /** * Gets a valid cron expression describing a schedule with a single * maintenance window, starting specified number of minutes after current @@ -350,13 +346,14 @@ public abstract class AbstractIntegrationTest { .actionType(actionType).forceTime(forcedTime).weight(weight).confirmationRequired(confirmationFlowActive) .build()) .toList(); - final List results = deploymentManagement.assignDistributionSets(deploymentRequests); + final List results = deploymentManagement.assignDistributionSets(deploymentRequests, null); assertThat(results).hasSize(1); return results.get(0); } protected List assignDistributionSets(final List requests) { - final List distributionSetAssignmentResults = deploymentManagement.assignDistributionSets(requests); + final List distributionSetAssignmentResults = + deploymentManagement.assignDistributionSets(requests, null); assertThat(distributionSetAssignmentResults).hasSize(requests.size()); return distributionSetAssignmentResults; } @@ -370,7 +367,7 @@ public abstract class AbstractIntegrationTest { } protected DistributionSetAssignmentResult makeAssignment(final DeploymentRequest request) { - final List results = deploymentManagement.assignDistributionSets(Collections.singletonList(request)); + final List results = deploymentManagement.assignDistributionSets(List.of(request), null); assertThat(results).hasSize(1); return results.get(0); } @@ -413,22 +410,22 @@ public abstract class AbstractIntegrationTest { } protected void enableMultiAssignments() { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, true); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, true); } protected void enableConfirmationFlow() { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.USER_CONFIRMATION_ENABLED, true); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED, true); } protected void disableConfirmationFlow() { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.USER_CONFIRMATION_ENABLED, false); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED, false); } protected boolean isConfirmationFlowActive() { return SecurityContextSwitch.getAs( SecurityContextSwitch.withUser("as_system", READ_TENANT_CONFIGURATION), - () -> tenantConfigurationManagement - .getConfigurationValue(TenantConfigurationKey.USER_CONFIRMATION_ENABLED, Boolean.class) + () -> tenantConfigurationManagement() + .getConfigurationValue(TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED, Boolean.class) .getValue()); } @@ -469,16 +466,16 @@ public abstract class AbstractIntegrationTest { } protected void enableBatchAssignments() { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED, true); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED, true); } protected void disableBatchAssignments() { - tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED, false); + tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED, false); } protected boolean isConfirmationFlowEnabled() { - return tenantConfigurationManagement - .getConfigurationValue(TenantConfigurationKey.USER_CONFIRMATION_ENABLED, Boolean.class).getValue(); + return tenantConfigurationManagement().getConfigurationValue(TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED, Boolean.class) + .getValue(); } // ensure that next action will get current time millis AFTER got from the previous diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CleanupTestExecutionListener.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CleanupTestExecutionListener.java index 8a441544d..f1e998273 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CleanupTestExecutionListener.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CleanupTestExecutionListener.java @@ -9,14 +9,13 @@ */ package org.eclipse.hawkbit.repository.test.util; -import java.util.List; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.event.EventPublisherHolder; -import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager.CacheEvictEvent; import org.springframework.context.ApplicationContext; import org.springframework.data.domain.PageRequest; @@ -36,26 +35,21 @@ public class CleanupTestExecutionListener extends AbstractTestExecutionListener @Override public void afterTestMethod(@NotNull final TestContext testContext) throws Exception { - SecurityContextSwitch.callAsPrivileged(() -> { + SecurityContextSwitch.asPrivileged(() -> { final ApplicationContext applicationContext = testContext.getApplicationContext(); - clearTestRepository( - applicationContext.getBean(SystemSecurityContext.class), - applicationContext.getBean(SystemManagement.class)); + clearTestRepository(applicationContext.getBean(SystemManagement.class)); return null; }); } - private void clearTestRepository( - final SystemSecurityContext systemSecurityContext, - final SystemManagement systemManagement) { - final List tenants = systemSecurityContext.runAsSystem(() -> systemManagement.findTenants(PAGE).getContent()); - tenants.forEach(tenant -> { + private void clearTestRepository(final SystemManagement systemManagement) { + asSystem(() -> systemManagement.forEachTenant(tenant -> { try { - systemSecurityContext.runAsSystem(() -> systemManagement.deleteTenant(tenant)); + asSystem(() -> systemManagement.deleteTenant(tenant)); } catch (final Exception e) { log.error("Error while delete tenant", e); } - }); + })); // evict global cache EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new CacheEvictEvent.Default(null, null, null)); } diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/SecurityContextSwitch.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/SecurityContextSwitch.java index bdeb7053b..956b749e2 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/SecurityContextSwitch.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/SecurityContextSwitch.java @@ -21,7 +21,7 @@ import java.util.function.Supplier; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.auth.SpPermission; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.tenancy.TenantAwareUser; @@ -56,7 +56,7 @@ public class SecurityContextSwitch { SecurityContextSwitch.systemManagement = systemManagement; } - public static T callAsPrivileged(final Callable callable) throws Exception { + public static T asPrivileged(final Callable callable) throws Exception { createTenant(DEFAULT_TENANT); return callAs(PRIVILEGED_USER, callable); } diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java index 8c45907c2..89f3d89a7 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.test.util; import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.hawkbit.context.AccessContext.asSystem; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -27,6 +28,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.stream.IntStream; import org.apache.commons.io.IOUtils; +import org.eclipse.hawkbit.context.AccessContext; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.Constants; import org.eclipse.hawkbit.repository.ControllerManagement; @@ -74,8 +76,6 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetType; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.context.annotation.Profile; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -160,8 +160,6 @@ public class TestdataFactory { private final RolloutManagement rolloutManagement; private final RolloutHandler rolloutHandler; private final QuotaManagement quotaManagement; - private final TenantAware tenantAware; - private final SystemSecurityContext systemSecurityContext; public TestdataFactory( final ControllerManagement controllerManagement, final ArtifactManagement artifactManagement, @@ -177,8 +175,7 @@ public class TestdataFactory { final TargetTagManagement targetTagManagement, final DeploymentManagement deploymentManagement, final RolloutManagement rolloutManagement, final RolloutHandler rolloutHandler, - final QuotaManagement quotaManagement, - final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) { + final QuotaManagement quotaManagement) { this.controllerManagement = controllerManagement; this.softwareModuleManagement = softwareModuleManagement; this.softwareModuleTypeManagement = softwareModuleTypeManagement; @@ -195,8 +192,6 @@ public class TestdataFactory { this.rolloutManagement = rolloutManagement; this.rolloutHandler = rolloutHandler; this.quotaManagement = quotaManagement; - this.tenantAware = tenantAware; - this.systemSecurityContext = systemSecurityContext; } private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -1289,11 +1284,11 @@ public class TestdataFactory { } private void rolloutHandleAll() { - final String tenant = tenantAware.getCurrentTenant(); + final String tenant = AccessContext.tenant(); if (tenant == null) { - throw new IllegalStateException("Tenant is null"); + throw new IllegalStateException("AccessContext is null"); } - systemSecurityContext.runAsSystem(rolloutHandler::handleAll); + asSystem(rolloutHandler::handleAll); } private Rollout reloadRollout(final Rollout rollout) { diff --git a/hawkbit-rest-core/pom.xml b/hawkbit-rest-core/pom.xml index 7a9494427..24e066f0c 100644 --- a/hawkbit-rest-core/pom.xml +++ b/hawkbit-rest-core/pom.xml @@ -27,11 +27,6 @@ hawkbit-core ${project.version} - - org.eclipse.hawkbit - hawkbit-security-core - ${project.version} - org.eclipse.hawkbit hawkbit-artifact-api @@ -42,6 +37,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.security + spring-security-web + org.springframework.hateoas spring-hateoas diff --git a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/SecurityManagedConfiguration.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/SecurityManagedConfiguration.java index 1a8f8d29e..6e52308fb 100644 --- a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/SecurityManagedConfiguration.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/SecurityManagedConfiguration.java @@ -32,7 +32,7 @@ import org.springframework.security.web.firewall.StrictHttpFirewall; import org.springframework.util.CollectionUtils; /** - * All configurations related to HawkBit's authentication and authorization layer. + * All configurations related to HawkBit's auth and authorization layer. */ @Slf4j @Configuration diff --git a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/security/DosFilter.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/security/DosFilter.java index 1c1fba4bf..7fcb02eca 100644 --- a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/security/DosFilter.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/security/DosFilter.java @@ -9,6 +9,8 @@ */ package org.eclipse.hawkbit.rest.security; +import static org.eclipse.hawkbit.audit.SecurityLogger.LOGGER; + import java.io.IOException; import java.util.Collection; import java.util.concurrent.TimeUnit; @@ -23,32 +25,23 @@ import jakarta.servlet.http.HttpServletResponse; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.security.SecurityConstants; -import org.eclipse.hawkbit.util.IpUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.eclipse.hawkbit.utils.IpUtil; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.util.AntPathMatcher; import org.springframework.web.filter.OncePerRequestFilter; /** - * Filter for protection against denial of service attacks. It reduces the - * maximum number of request per seconds which can be separately configured for - * read (GET) and write (PUT/POST/DELETE) requests. + * Filter for protection against Denial-of-Service (DoS) attacks. It reduces the maximum number of request per seconds which can be separately + * configured for read (GET) and write (PUT/POST/DELETE) requests. */ @Slf4j public class DosFilter extends OncePerRequestFilter { - private static final Logger LOG_DOS = - LoggerFactory.getLogger(SecurityConstants.SECURITY_LOG_PREFIX + ".dos"); - private static final Logger LOG_BLACKLIST = - LoggerFactory.getLogger(SecurityConstants.SECURITY_LOG_PREFIX + ".blacklist"); - private final AntPathMatcher antMatcher = new AntPathMatcher(); private final Collection includeAntPaths; - private final Pattern ipAdressBlacklist; + private final Pattern ipAddressBlacklist; private final Cache readCountCache = Caffeine.newBuilder() .expireAfterWrite(1, TimeUnit.SECONDS).build(); @@ -67,17 +60,14 @@ public class DosFilter extends OncePerRequestFilter { * Filter constructor including configuration. * * @param includeAntPaths paths where filter should hit - * @param maxRead Maximum number of allowed REST read/GET requests per second - * per client - * @param maxWrite Maximum number of allowed REST write/(PUT/POST/etc.) requests - * per second per client - * @param ipDosWhiteListPattern {@link Pattern} with with white list of peer IP addresses for - * DOS filter + * @param maxRead Maximum number of allowed REST read/GET requests per second per client + * @param maxWrite Maximum number of allowed REST write/(PUT/POST/etc.) requests per second per client + * @param ipDosWhiteListPattern {@link Pattern} with with white list of peer IP addresses for DOS filter * @param ipBlackListPattern {@link Pattern} with black listed IP addresses - * @param forwardHeader the header containing the forwarded IP address e.g. - * {@code x-forwarded-for} + * @param forwardHeader the header containing the forwarded IP address e.g. {@code x-forwarded-for} */ - public DosFilter(final Collection includeAntPaths, final int maxRead, final int maxWrite, + public DosFilter( + final Collection includeAntPaths, final int maxRead, final int maxWrite, final String ipDosWhiteListPattern, final String ipBlackListPattern, final String forwardHeader) { this.includeAntPaths = includeAntPaths; this.maxRead = maxRead; @@ -85,9 +75,9 @@ public class DosFilter extends OncePerRequestFilter { this.forwardHeader = forwardHeader; if (ipBlackListPattern != null && !ipBlackListPattern.isEmpty()) { - ipAdressBlacklist = Pattern.compile(ipBlackListPattern); + ipAddressBlacklist = Pattern.compile(ipBlackListPattern); } else { - ipAdressBlacklist = null; + ipAddressBlacklist = null; } if (ipDosWhiteListPattern != null && !ipDosWhiteListPattern.isEmpty()) { @@ -98,9 +88,8 @@ public class DosFilter extends OncePerRequestFilter { } @Override - protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, - final FilterChain filterChain) throws ServletException, IOException { - + protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) + throws ServletException, IOException { if (!shouldInclude(request)) { filterChain.doFilter(request, response); return; @@ -156,8 +145,8 @@ public class DosFilter extends OncePerRequestFilter { * processing of the request if forbidden */ private boolean checkAgainstBlacklist(final HttpServletResponse response, final String ip) { - if (ipAdressBlacklist != null && ipAdressBlacklist.matcher(ip).find()) { - LOG_BLACKLIST.info("Blacklisted client ({}) tries to access the server!", ip); + if (ipAddressBlacklist != null && ipAddressBlacklist.matcher(ip).find()) { + LOGGER.info("[BLACKLIST] Blacklisted client ({}) tries to access the server!", ip); response.setStatus(HttpStatus.FORBIDDEN.value()); return false; } @@ -171,8 +160,7 @@ public class DosFilter extends OncePerRequestFilter { if (count == null) { writeCountCache.put(ip, new AtomicInteger()); } else if (count.getAndIncrement() > maxWrite) { - LOG_DOS.info("Registered DOS attack! Client {} is above configured WRITE request threshold ({})!", ip, - maxWrite); + LOGGER.info("[DOS] Registered DOS attack! Client {} is above configured WRITE request threshold ({})!", ip, maxWrite); response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value()); processChain = false; } @@ -187,12 +175,11 @@ public class DosFilter extends OncePerRequestFilter { if (count == null) { readCountCache.put(ip, new AtomicInteger()); } else if (count.getAndIncrement() > maxRead) { - LOG_DOS.info("Registered DOS attack! Client {} is above configured READ request threshold ({})!", ip, - maxRead); + LOGGER.info("[DOS] Registered DOS attack! Client {} is above configured READ request threshold ({})!", ip, maxRead); response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value()); processChain = false; } return processChain; } -} +} \ No newline at end of file diff --git a/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/HawkbitClient.java b/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/HawkbitClient.java index c67fb7309..9efa45985 100644 --- a/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/HawkbitClient.java +++ b/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/HawkbitClient.java @@ -106,7 +106,7 @@ public class HawkbitClient { template.header(AUTHORIZATION, "GatewayToken " + tenant.getGatewayToken()); } else if (!ObjectUtils.isEmpty(controller.getSecurityToken())) { template.header(AUTHORIZATION, "TargetToken " + controller.getSecurityToken()); - } // else do not send authentication, no auth or certificate based + } // else do not send auth, no auth or certificate based }; // @formatter:on private static final ErrorDecoder DEFAULT_ERROR_DECODER_0 = new ErrorDecoder.Default(); @@ -279,7 +279,7 @@ public class HawkbitClient { (controller == null ? hawkBitServer.getMgmtUrl() : hawkBitServer.getDdiUrl()) + path).openConnection(); conn.setRequestMethod("POST"); - // deal with authentication - only from headers1 + // deal with auth - only from headers1 final RequestTemplate requestTemplate = new RequestTemplate(); requestInterceptorFn.apply(tenant, controller).apply(requestTemplate); requestTemplate.headers().forEach((k, v) -> v.forEach(e -> conn.setRequestProperty(k, e))); diff --git a/hawkbit-sdk/hawkbit-sdk-device/src/main/java/org/eclipse/hawkbit/sdk/device/DdiTenant.java b/hawkbit-sdk/hawkbit-sdk-device/src/main/java/org/eclipse/hawkbit/sdk/device/DdiTenant.java index bbb89ab1e..1173478be 100644 --- a/hawkbit-sdk/hawkbit-sdk-device/src/main/java/org/eclipse/hawkbit/sdk/device/DdiTenant.java +++ b/hawkbit-sdk/hawkbit-sdk-device/src/main/java/org/eclipse/hawkbit/sdk/device/DdiTenant.java @@ -19,7 +19,7 @@ import org.eclipse.hawkbit.sdk.HawkbitClient; import org.eclipse.hawkbit.sdk.Tenant; /** - * An in-memory simulated DDI Tenant to hold the controller twins in + * An in-memory simulated DDI AccessContext to hold the controller twins in * memory and be able to retrieve them again. */ public class DdiTenant { diff --git a/hawkbit-sdk/hawkbit-sdk-mgmt/src/main/java/org/eclipse/hawkbit/sdk/mgmt/AuthenticationSetupHelper.java b/hawkbit-sdk/hawkbit-sdk-mgmt/src/main/java/org/eclipse/hawkbit/sdk/mgmt/AuthenticationSetupHelper.java index f9b0ae257..a8c12c478 100644 --- a/hawkbit-sdk/hawkbit-sdk-mgmt/src/main/java/org/eclipse/hawkbit/sdk/mgmt/AuthenticationSetupHelper.java +++ b/hawkbit-sdk/hawkbit-sdk-mgmt/src/main/java/org/eclipse/hawkbit/sdk/mgmt/AuthenticationSetupHelper.java @@ -32,17 +32,17 @@ import org.eclipse.hawkbit.sdk.ca.CA; import org.springframework.util.ObjectUtils; /** - * Helper for authentication setup + * Helper for auth setup */ @Slf4j @AllArgsConstructor public class AuthenticationSetupHelper { - private static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY = "authentication.gatewaytoken.key"; - private static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED = "authentication.gatewaytoken.enabled"; - private static final String AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED = "authentication.targettoken.enabled"; - private static final String AUTHENTICATION_MODE_HEADER_ENABLED = "authentication.header.enabled"; - private static final String AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME = "authentication.header.authority"; + private static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY = "auth.gatewaytoken.key"; + private static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED = "auth.gatewaytoken.enabled"; + private static final String AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED = "auth.targettoken.enabled"; + private static final String AUTHENTICATION_MODE_HEADER_ENABLED = "auth.header.enabled"; + private static final String AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME = "auth.header.authority"; private static final Random RND = new SecureRandom(); @@ -57,7 +57,7 @@ public class AuthenticationSetupHelper { return Base64.getEncoder().encodeToString(rnd); } - // sets up a certificate authentication, if DdiCA is null - generate self signed CA + // sets up a certificate auth, if DdiCA is null - generate self signed CA public void setupCertificateAuthentication() throws CertificateException { final MgmtTenantManagementRestApi mgmtTenantManagementRestApi = hawkbitClient.mgmtService(MgmtTenantManagementRestApi.class, tenant); CA ddiCA = tenant.getDdiCA(); @@ -80,7 +80,7 @@ public class AuthenticationSetupHelper { } } - // enables secure token authentication + // enables secure token auth public void setupSecureTokenAuthentication() { final MgmtTenantManagementRestApi mgmtTenantManagementRestApi = hawkbitClient.mgmtService(MgmtTenantManagementRestApi.class, tenant); if (!(Boolean.TRUE.equals(Objects.requireNonNull(mgmtTenantManagementRestApi @@ -90,7 +90,7 @@ public class AuthenticationSetupHelper { } } - // set gateway token authentication (generate and sets gateway token to tenant, if not set up) + // set gateway token auth (generate and sets gateway token to tenant, if not set up) // return the gateway token public void setupGatewayTokenAuthentication() { String gatewayToken = tenant.getGatewayToken(); @@ -112,8 +112,8 @@ public class AuthenticationSetupHelper { } } - // if gateway token is configured then the gateway auth is enabled, so all devices use gateway token authentication. - // otherwise, target token authentication is enabled - then all devices shall be registered and the target token shall be set to the one from + // if gateway token is configured then the gateway auth is enabled, so all devices use gateway token auth. + // otherwise, target token auth is enabled - then all devices shall be registered and the target token shall be set to the one from // the DDI controller instance public void setupTargetAuthentication() { final String gatewayToken = tenant.getGatewayToken(); diff --git a/hawkbit-security-core/pom.xml b/hawkbit-security-core/pom.xml deleted file mode 100644 index f7f72f046..000000000 --- a/hawkbit-security-core/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - 4.0.0 - - org.eclipse.hawkbit - hawkbit-parent - ${revision} - - - hawkbit-security-core - hawkBit :: Security :: Core - - - - org.eclipse.hawkbit - hawkbit-core - ${project.version} - - - - org.springframework.boot - spring-boot-autoconfigure - - - org.springframework.security - spring-security-oauth2-core - - - org.springframework.security - spring-security-aspects - - - org.springframework.security - spring-security-web - - - org.springframework.data - spring-data-commons - - - - jakarta.servlet - jakarta.servlet-api - provided - - - - com.fasterxml.jackson.core - jackson-databind - - - \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditContextProvider.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditContextProvider.java deleted file mode 100644 index 160d01a00..000000000 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/audit/AuditContextProvider.java +++ /dev/null @@ -1,50 +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.audit; - -import java.util.Optional; - -import lombok.NoArgsConstructor; -import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.AuditorAware; - -@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE) -@SuppressWarnings("java:S6548") // java:S6548 - singleton holder ensures static access to spring resources in some places -public class AuditContextProvider { - - private static final AuditContextProvider INSTANCE = new AuditContextProvider(); - - private TenantAware.TenantResolver resolver; - private AuditorAware auditorAware; - - public static AuditContextProvider getInstance() { - return INSTANCE; - } - - @Autowired - public void setTenantResolver(final TenantAware.TenantResolver resolver) { - this.resolver = resolver; - } - - @Autowired - public void setAuditorAware(final AuditorAware auditorAware) { - this.auditorAware = auditorAware; - } - - public AuditContext getAuditContext() { - return new AuditContext( - Optional.ofNullable(resolver.resolveTenant()).orElse("n/a"), - Optional.ofNullable(auditorAware).flatMap(AuditorAware::getCurrentAuditor).orElse(SecurityContextTenantAware.SYSTEM_USER)); - } - - public record AuditContext(String tenant, String username) {} -} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java deleted file mode 100644 index 97d00b303..000000000 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2020 Bosch.IO 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.security; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; - -/** - * An implementation of the {@link UserAuthoritiesResolver} that is based on in-memory user permissions. - */ -public class InMemoryUserAuthoritiesResolver implements UserAuthoritiesResolver { - - private final Map> usernamesToAuthorities; - - /** - * Constructs the resolver based on the given authority lookup map. - * - * @param usernamesToAuthorities The authority map to read from. Must not be null. - */ - public InMemoryUserAuthoritiesResolver(final Map> usernamesToAuthorities) { - this.usernamesToAuthorities = usernamesToAuthorities; - } - - @Override - public Collection getUserAuthorities(final String username) { - // we can ignore the tenant here (no multi-tenancy by default) - final Collection authorities = usernamesToAuthorities.get(username); - if (authorities == null) { - return Collections.emptyList(); - } - return authorities; - } -} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java deleted file mode 100644 index b04c34342..000000000 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java +++ /dev/null @@ -1,242 +0,0 @@ -/** - * Copyright (c) 2023 Bosch.IO 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.security; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serial; -import java.io.Serializable; -import java.util.Base64; -import java.util.Collection; -import java.util.Objects; -import java.util.stream.Stream; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.AccessLevel; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.eclipse.hawkbit.security.SpringSecurityAuditorAware.AuditorAwarePrincipal; -import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.tenancy.TenantAwareUser; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; - -// serializer for security contexts used for background tasks (processing auto assignments and rollouts) -// the user context is serialized on task creation and then is deserialized and applied when task is executed later -public interface SecurityContextSerializer { - - /** - * Serializer that do not serialize (returns null on {@link #serialize(SecurityContext)}) and - * throws exception on {@link #deserialize(String)}. - */ - SecurityContextSerializer NOP = new Nop(); - /** - * Serializer the uses JSON serialization. - */ - SecurityContextSerializer JSON_SERIALIZATION = new JsonSerialization(); - - /** - * Return security context as string (could be just a reference) - * - * @param securityContext the security context - * @return the securityContext as string - */ - String serialize(SecurityContext securityContext); - - /** - * Deserialize security context - * - * @param securityContextString string representing the security context - * @return deserialized security context - */ - SecurityContext deserialize(String securityContextString); - - /** - * Empty implementation. Could be used if the serialization shall not be used. - * It returns null as serialized context and throws exception if - * someone try to deserialize anything. - */ - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class Nop implements SecurityContextSerializer { - - @Override - public String serialize(final SecurityContext securityContext) { - return null; - } - - @Override - public SecurityContext deserialize(final String securityContextString) { - throw new UnsupportedOperationException(); - } - } - - /** - * Implementation based on the java serialization. - */ - @NoArgsConstructor(access = AccessLevel.PRIVATE) - @SuppressWarnings("java:S112") // accepted - class JsonSerialization implements SecurityContextSerializer { - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - @Override - public String serialize(final SecurityContext securityContext) { - Objects.requireNonNull(securityContext); - try { - return OBJECT_MAPPER.writeValueAsString(new SecCtxInfo(securityContext)); - } catch (final JsonProcessingException e) { - throw new RuntimeException(e); - } - } - - @Override - public SecurityContext deserialize(final String securityContextString) { - Objects.requireNonNull(securityContextString); - final String securityContextTrimmed = securityContextString.trim(); - try { - return OBJECT_MAPPER.readerFor(SecCtxInfo.class). readValue(securityContextTrimmed).toSecurityContext(); - } catch (final JsonProcessingException e) { - throw new RuntimeException(e); - } - } - - // simplified info for the security context keeping just the basic info needed for background execution of - // controller authentication is not supported - always is false - // only authenticated user is supported - @NoArgsConstructor - @Data - private static class SecCtxInfo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - private String tenant; - // auditor / username (authentication principal name) - private String auditor = "n/a"; // default value "n/a" is used only on deserialization if field is missing - @JsonProperty(required = true) - private String[] authorities; - - SecCtxInfo(final SecurityContext securityContext) { - final Authentication authentication = securityContext.getAuthentication(); - if (!authentication.isAuthenticated()) { - throw new IllegalStateException("Only authenticated context could be serialized"); - } - if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails) { - if (tenantAwareDetails.controller()) { - throw new IllegalStateException("Controller authentication context is not supported"); - } - tenant = tenantAwareDetails.tenant(); - } else if (authentication.getPrincipal() instanceof TenantAwareUser tenantAwareUser) { - tenant = tenantAwareUser.getTenant(); - } - - // keep the auditor, ofr audit purposes, - // sets principal to the resolved auditor and then deserialized authentication will return it as principal - // since the class is not known to auditor aware - it shall used default - principal as auditor - auditor = SpringSecurityAuditorAware.resolveAuditor(authentication); - authorities = authentication.getAuthorities().stream().map(Object::toString).toArray(String[]::new); - } - - // TODO - remove it in future - // auditor alias, allows setting for auditor also as username (so supported auditor/username in json) - @JsonSetter("username") - private void setUsername(final String username) { - this.auditor = username; - } - - private SecurityContext toSecurityContext() { - final SecurityContext ctx = SecurityContextHolder.createEmptyContext(); - final Object details = tenant == null ? null : new TenantAwareAuthenticationDetails(tenant, false); - final AuditorAwarePrincipal principal = () -> auditor; - final Collection grantedAuthorities = - Stream.of(authorities).map(SimpleGrantedAuthority::new).toList(); - ctx.setAuthentication(new Authentication() { - - @Override - public Object getPrincipal() { - return principal; - } - - @Override - public Collection getAuthorities() { - return grantedAuthorities; - } - - @Override - public boolean isAuthenticated() { - return true; - } - - @Override - public Object getDetails() { - return details; - } - - @Override - public Object getCredentials() { - return null; - } - - @Override - public void setAuthenticated(final boolean isAuthenticated) throws IllegalArgumentException { - throw new UnsupportedOperationException(); - } - - @Override - public String getName() { - return auditor; - } - }); - return ctx; - } - } - } - - /** - * Implementation based on the java serialization. - */ - @NoArgsConstructor(access = AccessLevel.PRIVATE) - @SuppressWarnings("java:S112") // accepted - class JavaSerialization implements SecurityContextSerializer { - - @Override - public String serialize(final SecurityContext securityContext) { - Objects.requireNonNull(securityContext); - try (final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final ObjectOutputStream oos = new ObjectOutputStream(baos)) { - oos.writeObject(securityContext); - oos.flush(); - return Base64.getEncoder().encodeToString(baos.toByteArray()); - } catch (final IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public SecurityContext deserialize(final String securityContextString) { - Objects.requireNonNull(securityContextString); - try (final ByteArrayInputStream bais = new ByteArrayInputStream(Base64.getDecoder().decode(securityContextString)); - final ObjectInputStream ois = new ObjectInputStream(bais)) { - return (SecurityContext) ois.readObject(); - } catch (final IOException | ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - } -} 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 deleted file mode 100644 index 5cca8b524..000000000 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java +++ /dev/null @@ -1,254 +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.security; - -import java.io.Serial; -import java.util.Collection; -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; - -import org.eclipse.hawkbit.ContextAware; -import org.eclipse.hawkbit.im.authentication.SpRole; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.tenancy.TenantAwareUser; -import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver; -import org.springframework.lang.Nullable; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.oauth2.core.oidc.user.OidcUser; - -/** - * A {@link ContextAware} (hence of {@link TenantAware}) that uses spring security context propagation - * mechanisms and which retrieves the ID of the tenant from the {@link SecurityContext#getAuthentication()} - * {@link Authentication#getDetails()} which holds the {@link TenantAwareAuthenticationDetails} object. - */ -public class SecurityContextTenantAware implements ContextAware { - - // Note! no system user shall be used as a regular user! - public static final String SYSTEM_USER = "system"; - - private static final Collection SYSTEM_AUTHORITIES = List.of(new SimpleGrantedAuthority(SpRole.SYSTEM_ROLE)); - - private final UserAuthoritiesResolver authoritiesResolver; - private final SecurityContextSerializer securityContextSerializer; - private final TenantResolver tenantResolver; - - /** - * Creates the {@link SecurityContextTenantAware} based on the given {@link UserAuthoritiesResolver}. - * - * @param authoritiesResolver Resolver to retrieve the authorities for a given user. Must not be null.. - */ - public SecurityContextTenantAware(final UserAuthoritiesResolver authoritiesResolver) { - this(authoritiesResolver, null, null); - } - - /** - * Creates the {@link SecurityContextTenantAware} based on the given {@link UserAuthoritiesResolver}. - * - * @param authoritiesResolver Resolver to retrieve the authorities for a given user. Must not be null. - * @param securityContextSerializer Serializer that is used to serialize / deserialize {@link SecurityContext}s. - */ - public SecurityContextTenantAware( - final UserAuthoritiesResolver authoritiesResolver, @Nullable final SecurityContextSerializer securityContextSerializer) { - this(authoritiesResolver, securityContextSerializer, null); - } - - /** - * Creates the {@link SecurityContextTenantAware} based on the given {@link UserAuthoritiesResolver}. - * - * @param authoritiesResolver Resolver to retrieve the authorities for a given user. Must not be null. - * @param securityContextSerializer Serializer that is used to serialize / deserialize {@link SecurityContext}s. - */ - public SecurityContextTenantAware( - final UserAuthoritiesResolver authoritiesResolver, @Nullable final SecurityContextSerializer securityContextSerializer, - @Nullable final TenantResolver tenantResolver) { - this.authoritiesResolver = authoritiesResolver; - this.securityContextSerializer = securityContextSerializer == null ? SecurityContextSerializer.NOP : securityContextSerializer; - this.tenantResolver = tenantResolver == null ? new DefaultTenantResolver() : tenantResolver; - } - - @Override - public String getCurrentTenant() { - return tenantResolver.resolveTenant(); - } - - @Override - public String getCurrentUsername() { - final SecurityContext context = SecurityContextHolder.getContext(); - if (context.getAuthentication() != null) { - final Object principal = context.getAuthentication().getPrincipal(); - if (principal instanceof OidcUser oidcUser) { - return oidcUser.getPreferredUsername(); - } - if (principal instanceof User user) { - return user.getUsername(); - } - } - return null; - } - - @Override - @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 void runAsTenantAsUser(final String tenant, final String username, final Runnable runnable) { - Objects.requireNonNull(tenant); - Objects.requireNonNull(username); - - final List authorities = runAsTenant( - tenant, - () -> authoritiesResolver.getUserAuthorities(username).stream() - .map(SimpleGrantedAuthority::new) - .toList()); - runInContext(buildUserSecurityContext(tenant, username, authorities), () -> { - runnable.run(); - return null; - }); - } - - @Override - public Optional getCurrentContext() { - return Optional.ofNullable(SecurityContextHolder.getContext()).map(securityContextSerializer::serialize); - } - - @Override - public R runInContext(final String serializedContext, final Function function, final T t) { - Objects.requireNonNull(serializedContext); - Objects.requireNonNull(function); - final SecurityContext securityContext = securityContextSerializer.deserialize(serializedContext); - Objects.requireNonNull(securityContext); - - return runInContext(securityContext, () -> function.apply(t)); - } - - private static T runInContext(final SecurityContext securityContext, final Supplier supplier) { - final SecurityContext originalContext = SecurityContextHolder.getContext(); - if (Objects.equals(securityContext, originalContext)) { - return supplier.get(); - } else { - SecurityContextHolder.setContext(securityContext); - try { - return MdcHandler.getInstance().callWithAuthRE(supplier::get); - } finally { - SecurityContextHolder.setContext(originalContext); - } - } - } - - private static SecurityContext buildUserSecurityContext( - final String tenant, final String username, final Collection authorities) { - final SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); - securityContext.setAuthentication(new AuthenticationDelegate( - SecurityContextHolder.getContext().getAuthentication(), tenant, username, authorities)); - return securityContext; - } - - /** - * An {@link Authentication} implementation to delegate to an existing {@link Authentication} object except setting the details - * specifically for a specific tenant and user. - */ - private static final class AuthenticationDelegate implements Authentication { - - @Serial - private static final long serialVersionUID = 1L; - - private final Authentication delegate; - private final TenantAwareUser principal; - private final TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails; - - private AuthenticationDelegate( - final Authentication delegate, final String tenant, final String username, - final Collection authorities) { - this.delegate = delegate; - principal = new TenantAwareUser(username, username, authorities, tenant); - tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false); - } - - @Override - public int hashCode() { - return delegate != null ? delegate.hashCode() : -1; - } - - @Override - public boolean equals(final Object another) { - if (another instanceof Authentication anotherAuthentication) { - return Objects.equals(delegate, anotherAuthentication) && - Objects.equals(principal, anotherAuthentication.getPrincipal()) && - Objects.equals(tenantAwareAuthenticationDetails, anotherAuthentication.getDetails()); - } else { - return false; - } - } - - @Override - public String toString() { - return delegate != null ? delegate.toString() : null; - } - - @Override - public String getName() { - return delegate != null ? delegate.getName() : null; - } - - @Override - public Collection getAuthorities() { - return delegate != null ? delegate.getAuthorities() : Collections.emptyList(); - } - - @Override - public Object getCredentials() { - return delegate != null ? delegate.getCredentials() : null; - } - - @Override - public Object getDetails() { - return tenantAwareAuthenticationDetails; - } - - @Override - public Object getPrincipal() { - return principal; - } - - @Override - public boolean isAuthenticated() { - return delegate == null || delegate.isAuthenticated(); - } - - @Override - public void setAuthenticated(final boolean isAuthenticated) { - if (delegate == null) { - return; - } - delegate.setAuthenticated(isAuthenticated); - } - } -} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java deleted file mode 100644 index 5529baebc..000000000 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java +++ /dev/null @@ -1,87 +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.security; - -import java.util.Optional; - -import lombok.NonNull; -import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; -import org.springframework.data.domain.AuditorAware; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.oauth2.core.oidc.user.OidcUser; - -/** - * Auditor class that allows BaseEntity-s to insert current logged in user for repository changes. - */ -public class SpringSecurityAuditorAware implements AuditorAware { - - // Sometimes 'system' need to override the auditor when do create/modify actions in context of a tenant and user. - // Though this could be made using runAsTenantAsUser sometimes (as in transaction) this override is needed - // after runAsTenantAsUser (because it seems that auditor is got in commit time). - // So this thread local variable provides option to override explicitly the auditor. - private static final ThreadLocal AUDITOR_OVERRIDE = new ThreadLocal<>(); - - // Always shall be followed by {@link #clearAuditorOverride} - public static void setAuditorOverride(final String auditor) { - if (auditor == null) { - AUDITOR_OVERRIDE.remove(); - } else { - AUDITOR_OVERRIDE.set(auditor); - } - } - - public static void clearAuditorOverride() { - AUDITOR_OVERRIDE.remove(); - } - - @NonNull - @Override - public Optional getCurrentAuditor() { - if (AUDITOR_OVERRIDE.get() != null) { - return Optional.of(AUDITOR_OVERRIDE.get()); - } - - final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - - if (isAuthenticationInvalid(authentication)) { - return Optional.empty(); - } - - return Optional.ofNullable(resolveAuditor(authentication)); - } - - public static String resolveAuditor(final Authentication authentication) { - if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails && tenantAwareDetails.controller()) { - return "CONTROLLER_PLUG_AND_PLAY"; - } - final Object principal = authentication.getPrincipal(); - if (principal instanceof AuditorAwarePrincipal auditorAwarePrincipal) { - return auditorAwarePrincipal.getAuditor(); - } - if (principal instanceof UserDetails userDetails) { - return userDetails.getUsername(); - } - if (principal instanceof OidcUser oidcUser) { - return oidcUser.getPreferredUsername(); - } - return principal.toString(); - } - - private static boolean isAuthenticationInvalid(final Authentication authentication) { - return authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() == null; - } - - public interface AuditorAwarePrincipal { - - String getAuditor(); - } -} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java deleted file mode 100644 index 92a4c2f4c..000000000 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java +++ /dev/null @@ -1,263 +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.security; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serial; -import java.io.Serializable; -import java.util.Collection; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.Callable; - -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; - -import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.im.authentication.SpRole; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; -import org.springframework.security.access.hierarchicalroles.RoleHierarchy; -import org.springframework.security.authentication.AnonymousAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.util.ObjectUtils; - -/** - * A Service which provide to run system code. - */ -@Slf4j -public class SystemSecurityContext { - - private final TenantAware tenantAware; - private final RoleHierarchy roleHierarchy; - - public SystemSecurityContext(final TenantAware tenantAware) { - this(tenantAware, null); - } - - public SystemSecurityContext(final TenantAware tenantAware, final RoleHierarchy roleHierarchy) { - this.tenantAware = tenantAware; - this.roleHierarchy = roleHierarchy; - } - - /** - * Runs a given {@link Runnable} within a system security context, which is permitted to call secured system code. Often the system needs - * to call secured methods by its own without relying on the current security context e.g. if the current security context does not contain - * the necessary permission it's necessary to execute code as system code to execute necessary methods and functionality.
- * The security context will be switched to the system code and back after the callable is called.
- * The system code is executed for a current tenant by using the {@link TenantAware#getCurrentTenant()}. - * - * @param runnable the runnable to call within the system security context - */ - public void runAsSystem(final Runnable runnable) { - runAsSystemAsTenant(() -> { - runnable.run(); - return null; - }, tenantAware.getCurrentTenant()); - } - - /** - * Runs a given {@link Callable} within a system security context, which is permitted to call secured system code. Often the system needs - * to call secured methods by its own without relying on the current security context e.g. if the current security context does not contain - * the necessary permission it's necessary to execute code as system code to execute necessary methods and functionality.
- * The security context will be switched to the system code and back after the callable is called.
- * The system code is executed for a current tenant by using the {@link TenantAware#getCurrentTenant()}. - * - * @param callable the callable to call within the system security context - * @return the return value of the {@link Callable#call()} method. - */ - public T runAsSystem(final Callable callable) { - return runAsSystemAsTenant(callable, tenantAware.getCurrentTenant()); - } - - /** - * Runs a given {@link Callable} within a system security context, which is permitted to call secured system code. Often the system needs - * to call secured methods by its own without relying on the current security context e.g. if the current security context does not contain - * the necessary permission it's necessary to execute code as system code to execute necessary methods and functionality.
- * The security context will be switched to the system code and back after the callable is called.
- * The system code is executed for a specific given tenant by using the {@link TenantAware}. - * - * @param callable the callable to call within the system security context - * @param tenant the tenant to act as system code - * @return the return value of the {@link Callable#call()} method. - */ - // The callable API throws a Exception and not a specific one - @SuppressWarnings({ "squid:S2221", "squid:S00112" }) - public T runAsSystemAsTenant(final Callable callable, final String tenant) { - final SecurityContext oldContext = SecurityContextHolder.getContext(); - try { - log.debug("Entering system code execution"); - return tenantAware.runAsTenant(tenant, () -> { - setSystemContext(SecurityContextHolder.getContext()); - return MdcHandler.getInstance().callWithAuthRE(callable); - }); - } finally { - SecurityContextHolder.setContext(oldContext); - log.debug("Leaving system code execution"); - } - } - - /** - * Runs a given {@link Callable} within a system security context, which has the provided {@link GrantedAuthority}s to successfully - * run the {@link Callable}.
- * The security context will be switched to a new {@link SecurityContext} and back after the callable is called. - * - * @param tenant under which the {@link Callable#call()} must be executed. - * @param callable to call within the security context - * @return the return value of the {@link Callable#call()} method. - */ - public T runAsControllerAsTenant(@NotEmpty final String tenant, @NotNull final Callable callable) { - final SecurityContext oldContext = SecurityContextHolder.getContext(); - final List authorities = List.of(new SimpleGrantedAuthority(SpRole.CONTROLLER_ROLE_ANONYMOUS)); - try { - return tenantAware.runAsTenant(tenant, () -> { - setCustomSecurityContext(tenant, oldContext.getAuthentication().getPrincipal(), authorities); - return MdcHandler.getInstance().callWithAuthRE(callable); - }); - } finally { - SecurityContextHolder.setContext(oldContext); - } - } - - /** - * @return {@code true} if the current running code is running as system code block. - */ - public static boolean isCurrentThreadSystemCode() { - return SecurityContextHolder.getContext().getAuthentication() instanceof SystemCodeAuthentication; - } - - @SuppressWarnings("java:S3776") // java:S3776 - better in one place for better readability - public boolean hasPermission(final String permission) { - final SecurityContext context = SecurityContextHolder.getContext(); - if (context != null) { - final Authentication authentication = context.getAuthentication(); - if (authentication != null) { - Collection grantedAuthorities = authentication.getAuthorities(); - if (!ObjectUtils.isEmpty(grantedAuthorities)) { - if (roleHierarchy != null) { - grantedAuthorities = roleHierarchy.getReachableGrantedAuthorities(grantedAuthorities); - } - for (final GrantedAuthority authority : grantedAuthorities) { - if (authority.getAuthority().equals(permission)) { - return true; - } - } - } - } - } - return false; - } - - static void setSystemContext(final SecurityContext oldContext) { - final Authentication oldAuthentication = oldContext.getAuthentication(); - final SecurityContextImpl securityContextImpl = new SecurityContextImpl(); - securityContextImpl.setAuthentication(new SystemCodeAuthentication(oldAuthentication)); - SecurityContextHolder.setContext(securityContextImpl); - } - - private void setCustomSecurityContext( - final String tenantId, final Object principal, final Collection authorities) { - final AnonymousAuthenticationToken authenticationToken = new AnonymousAuthenticationToken( - UUID.randomUUID().toString(), principal, authorities); - authenticationToken.setDetails(new TenantAwareAuthenticationDetails(tenantId, true)); - final SecurityContextImpl securityContextImpl = new SecurityContextImpl(); - securityContextImpl.setAuthentication(authenticationToken); - SecurityContextHolder.setContext(securityContextImpl); - } - - /** - * An implementation of the Spring's {@link Authentication} object which is used within a system security code block and - * wraps the original authentication object. The wrapped object contains the necessary {@link SpRole#SYSTEM_ROLE} - * which is allowed to execute all secured methods. - */ - @SuppressWarnings("java:S4275") // java:S4275 - intentionally returns the "hold" objects - public static final class SystemCodeAuthentication implements Authentication { - - @Serial - private static final long serialVersionUID = 1L; - - private static final List AUTHORITIES = List.of(new SimpleGrantedAuthority(SpRole.SYSTEM_ROLE)); - - private final Holder credentials; - private final Holder details; - private final Holder principal; - - private SystemCodeAuthentication(final Authentication oldAuthentication) { - credentials = new Holder(oldAuthentication != null ? oldAuthentication.getCredentials() : null); - details = new Holder(oldAuthentication != null ? oldAuthentication.getDetails() : null); - principal = new Holder(oldAuthentication != null ? oldAuthentication.getPrincipal() : null); - } - - @Override - public String getName() { - return null; - } - - @Override - public Collection getAuthorities() { - return AUTHORITIES; - } - - @Override - public Object getCredentials() { - return credentials.obj; - } - - @Override - public Object getDetails() { - return details.obj; - } - - @Override - public Object getPrincipal() { - return principal.obj; - } - - @Override - public boolean isAuthenticated() { - return true; - } - - @Override - public void setAuthenticated(final boolean isAuthenticated) { - throw new UnsupportedOperationException(); - } - - // Serializable wrapper that ensures that the content will be serialized only if it is Serializable - private static class Holder implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - private Object obj; - - private Holder(final Object obj) { - this.obj = obj; - } - - @Serial - private void writeObject(final ObjectOutputStream oos) throws IOException { - oos.writeObject(obj instanceof Serializable ? obj : null); - } - - @Serial - private void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException { - obj = ois.readObject(); - } - } - } -} \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java deleted file mode 100644 index 861b63ba4..000000000 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2023 Bosch.IO 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.util; - -import java.nio.charset.StandardCharsets; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.springframework.web.util.UriUtils; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class UrlUtils { - - public static String decodeUriValue(String value) { - return UriUtils.decode(value, StandardCharsets.UTF_8); - } -} \ No newline at end of file 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 deleted file mode 100644 index 7d879c2dd..000000000 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SystemCodeAuthenticationTest.java +++ /dev/null @@ -1,126 +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.security; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -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; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; - -class SystemCodeAuthenticationTest { - - private static final SystemSecurityContext SYSTEM_SECURITY_CONTEXT = new SystemSecurityContext(new TenantAware() { - - @Override - public String getCurrentTenant() { - return "tenant"; - } - - @Override - public String getCurrentUsername() { - return "user"; - } - - @SneakyThrows - @Override - public T runAsTenant(final String tenant, final Callable callable) { - return callable.call(); - } - - @Override - public void runAsTenantAsUser(final String tenant, final String username, final Runnable runnable) { - runnable.run(); - } - }); - - @Test - void testSerializationWithoutNull() { - final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("test", "pass", List.of(new SimpleGrantedAuthority("anonymous"))); - auth.setDetails("string details"); - test(auth); - } - - @Test - void testSerializationWithNullPrincipal() { - final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(null, "pass", List.of(new SimpleGrantedAuthority("anonymous"))); - auth.setDetails("string details"); - test(auth); - } - - @Test - void testSerializationWithNullCredentials() { - final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("test", null, List.of(new SimpleGrantedAuthority("anonymous"))); - auth.setDetails("string details"); - test(auth); - } - - @Test - void testSerializationWithNullDetails() { - final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("test", "pass", List.of(new SimpleGrantedAuthority("anonymous"))); - auth.setDetails(null); - test(auth); - } - - @Test - void testSerializationWitAllNull() { - final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(null, null, List.of(new SimpleGrantedAuthority("anonymous"))); - auth.setDetails(null); - test(auth); - } - - private static void test(final UsernamePasswordAuthenticationToken auth) { - final SecurityContext sc = SecurityContextHolder.createEmptyContext(); - sc.setAuthentication(auth); - SecurityContextHolder.setContext(sc); - SYSTEM_SECURITY_CONTEXT.runAsSystemAsTenant(() -> { - final Authentication currentAuth = SecurityContextHolder.getContext().getAuthentication(); - Assertions.assertThat(currentAuth.getClass().getSimpleName()).isEqualTo("SystemCodeAuthentication"); - Assertions.assertThat(currentAuth.getPrincipal()).isEqualTo(auth.getPrincipal()); - Assertions.assertThat(currentAuth.getCredentials()).isEqualTo(auth.getCredentials()); - Assertions.assertThat(currentAuth.getAuthorities()).isEqualTo(List.of(new SimpleGrantedAuthority("ROLE_SYSTEM_CODE"))); - Assertions.assertThat(currentAuth.getDetails()).isEqualTo(auth.getDetails()); - - final Authentication serializedAndDeserializedAuth = serializeAndDeserialize(currentAuth); - Assertions.assertThat(serializedAndDeserializedAuth.getClass().getSimpleName()).isEqualTo("SystemCodeAuthentication"); - Assertions.assertThat(serializedAndDeserializedAuth.getPrincipal()).isEqualTo(auth.getPrincipal()); - Assertions.assertThat(serializedAndDeserializedAuth.getCredentials()).isEqualTo(auth.getCredentials()); - Assertions.assertThat(serializedAndDeserializedAuth.getAuthorities()).isEqualTo(List.of(new SimpleGrantedAuthority("ROLE_SYSTEM_CODE"))); - Assertions.assertThat(serializedAndDeserializedAuth.getDetails()).isEqualTo(auth.getDetails()); - return null; - }, "tenant"); - SecurityContextHolder.clearContext(); - } - - @SuppressWarnings("unchecked") - private static T serializeAndDeserialize(final T object) throws IOException, ClassNotFoundException { - try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - try (final ObjectOutputStream oos = new ObjectOutputStream(baos)) { - oos.writeObject(object); - oos.flush(); - } - try (final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { - return (T) ois.readObject(); - } - } - } -} \ No newline at end of file diff --git a/hawkbit-test-report/pom.xml b/hawkbit-test-report/pom.xml index 59d908dfc..ee35c519b 100644 --- a/hawkbit-test-report/pom.xml +++ b/hawkbit-test-report/pom.xml @@ -28,11 +28,6 @@ hawkbit-core ${project.version}
- - org.eclipse.hawkbit - hawkbit-security-core - ${project.version} - org.eclipse.hawkbit hawkbit-artifact-fs diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitUiApp.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitUiApp.java index 82aeafbd9..27a6cbf57 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitUiApp.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitUiApp.java @@ -9,6 +9,14 @@ */ package org.eclipse.hawkbit.ui; +import static feign.Util.ISO_8859_1; + +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Base64; +import java.util.Collections; +import java.util.Objects; + import com.vaadin.flow.component.page.AppShellConfigurator; import com.vaadin.flow.server.PWA; import com.vaadin.flow.theme.Theme; @@ -36,14 +44,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.core.oidc.user.OidcUser; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Base64; -import java.util.Collections; -import java.util.Objects; - -import static feign.Util.ISO_8859_1; - @Slf4j @Theme("hawkbit") @PWA(name = "hawkBit UI", shortName = "hawkBit UI") diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SimpleI18NProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SimpleI18NProvider.java index cf8831095..3a8924669 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SimpleI18NProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SimpleI18NProvider.java @@ -12,6 +12,7 @@ package org.eclipse.hawkbit.ui; import java.util.Arrays; import java.util.Locale; + import com.vaadin.flow.i18n.DefaultI18NProvider; import org.springframework.stereotype.Component; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/DistributionSetView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/DistributionSetView.java index ba696e4f5..ac1026811 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/DistributionSetView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/DistributionSetView.java @@ -20,8 +20,6 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.vaadin.flow.component.grid.GridSortOrder; -import com.vaadin.flow.data.provider.SortDirection; import jakarta.annotation.security.RolesAllowed; import com.vaadin.flow.component.Component; @@ -33,6 +31,7 @@ import com.vaadin.flow.component.checkbox.CheckboxGroup; import com.vaadin.flow.component.dependency.Uses; import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.grid.GridSortOrder; import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; @@ -40,6 +39,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.select.Select; import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.data.provider.SortDirection; import com.vaadin.flow.data.renderer.ComponentRenderer; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/TargetView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/TargetView.java index af8e067cc..5bedd7a26 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/TargetView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/TargetView.java @@ -25,10 +25,9 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.vaadin.flow.data.provider.ListDataProvider; import jakarta.annotation.security.RolesAllowed; +import com.fasterxml.jackson.databind.ObjectMapper; import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.ClickEvent; import com.vaadin.flow.component.Component; @@ -54,6 +53,7 @@ import com.vaadin.flow.component.select.Select; import com.vaadin.flow.component.tabs.TabSheet; import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.data.provider.ListDataProvider; import com.vaadin.flow.data.renderer.ComponentRenderer; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/util/TableView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/util/TableView.java index 0b956688e..dbea10340 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/util/TableView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/util/TableView.java @@ -33,7 +33,6 @@ import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.NavigationTrigger; import com.vaadin.flow.theme.lumo.LumoUtility; - import org.eclipse.hawkbit.ui.view.Constants; @SuppressWarnings("java:S119") // better readability diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/util/Utils.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/util/Utils.java index ff6a60f83..2aa544724 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/util/Utils.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/util/Utils.java @@ -28,15 +28,6 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.ToLongFunction; -import com.vaadin.flow.component.icon.Icon; -import com.vaadin.flow.component.icon.IconFactory; -import com.vaadin.flow.data.provider.QuerySortOrder; -import com.vaadin.flow.data.provider.SortDirection; -import com.vaadin.flow.data.renderer.LocalDateTimeRenderer; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType; -import org.eclipse.hawkbit.ui.view.Constants; - import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasValue; import com.vaadin.flow.component.Text; @@ -48,6 +39,8 @@ import com.vaadin.flow.component.confirmdialog.ConfirmDialog; import com.vaadin.flow.component.datetimepicker.DateTimePicker; import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.icon.Icon; +import com.vaadin.flow.component.icon.IconFactory; import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.notification.NotificationVariant; @@ -57,9 +50,15 @@ import com.vaadin.flow.component.select.Select; import com.vaadin.flow.component.shared.Tooltip; import com.vaadin.flow.component.textfield.NumberField; import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.data.provider.QuerySortOrder; +import com.vaadin.flow.data.provider.SortDirection; import com.vaadin.flow.data.renderer.ComponentRenderer; +import com.vaadin.flow.data.renderer.LocalDateTimeRenderer; import com.vaadin.flow.data.value.ValueChangeMode; import com.vaadin.flow.theme.lumo.LumoUtility; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType; +import org.eclipse.hawkbit.ui.view.Constants; @Slf4j public class Utils { diff --git a/pom.xml b/pom.xml index d54d8476f..584ee604a 100644 --- a/pom.xml +++ b/pom.xml @@ -725,7 +725,6 @@ hawkbit-ql-jpa hawkbit-core - hawkbit-security-core hawkbit-artifact hawkbit-repository hawkbit-rest-core