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 extends GrantedAuthority> 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 extends GrantedAuthority> grantedAuthorities =
+ Stream.of(authorities).map(SimpleGrantedAuthority::new).toList();
+ ctx.setAuthentication(new Authentication() {
+
+ @Override
+ public Object getPrincipal() {
+ return principal;
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> 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 extends GrantedAuthority> 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 extends Target> targetManagement;
private final SoftwareModuleManagement extends SoftwareModule> softwareModuleManagement;
private final DistributionSetManagement extends DistributionSet> 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 extends Target> targetManagement,
final SoftwareModuleManagement extends SoftwareModule> softwareModuleManagement,
final DistributionSetManagement extends DistributionSet> 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 extends Target> targetManagement,
final DistributionSetManagement extends DistributionSet> distributionSetManagement,
final SoftwareModuleManagement extends SoftwareModule> 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