CONTROLLER_AUTHORITY =
+ List.of(new SimpleGrantedAuthority(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
+ private final String controllerId;
+
+ AuthenticatedController(final String tenant, final String controllerId) {
+ super(CONTROLLER_AUTHORITY);
+ super.setDetails(new TenantAwareAuthenticationDetails(tenant, true));
+ this.controllerId = controllerId;
+ setAuthenticated(true);
+ }
+
+ @Override
+ public Object getCredentials() {
+ return null;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return controllerId;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerSecurityToken.java b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/ControllerSecurityToken.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerSecurityToken.java
rename to hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/ControllerSecurityToken.java
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
new file mode 100644
index 000000000..f82608f67
--- /dev/null
+++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticator.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2025 Contributors to the Eclipse Foundation
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.hawkbit.security.controller;
+
+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.slf4j.Logger;
+import org.springframework.security.core.Authentication;
+
+/**
+ * An authenticator which extracts (if enabled through configuration) the possibility to authenticate a target based through
+ * a gateway security token. This is commonly used for targets connected indirectly via a gateway. This gateway controls multiple targets
+ * under the gateway security token which can be set via the {@code Authorization} header.
+ *
+ * {@code Example Header: Authorization: GatewayToken 5d8fSD54fdsFG98DDsa.}
+ */
+@Slf4j
+public class GatewayTokenAuthenticator extends Authenticator.AbstractAuthenticator {
+
+ public static final String GATEWAY_SECURITY_TOKEN_AUTH_SCHEME = "GatewayToken ";
+ private static final int OFFSET_GATEWAY_TOKEN = GATEWAY_SECURITY_TOKEN_AUTH_SCHEME.length();
+
+ private final TenantAware.TenantRunner gatewaySecurityTokenKeyConfigRunner;
+
+ public GatewayTokenAuthenticator(
+ final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
+ final SystemSecurityContext systemSecurityContext) {
+ super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
+ gatewaySecurityTokenKeyConfigRunner = () -> {
+ log.trace("retrieving configuration value for configuration key {}",
+ TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY);
+
+ return systemSecurityContext
+ .runAsSystem(() -> tenantConfigurationManagement
+ .getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class)
+ .getValue());
+ };
+ }
+
+ @Override
+ public Authentication authenticate(final ControllerSecurityToken controllerSecurityToken) {
+ final String authHeader = controllerSecurityToken.getHeader(ControllerSecurityToken.AUTHORIZATION_HEADER);
+ if (authHeader == null) {
+ log.debug("The request doesn't contain the 'authorization' header");
+ return null;
+ } else if (!authHeader.startsWith(GATEWAY_SECURITY_TOKEN_AUTH_SCHEME)) {
+ log.debug("The request contains the 'authorization' header but it doesn't start with '{}'", GATEWAY_SECURITY_TOKEN_AUTH_SCHEME);
+ return null;
+ }
+
+ if (!isEnabled(controllerSecurityToken)) {
+ log.debug("The gateway token authentication is disabled");
+ return null;
+ }
+
+ log.debug("Found 'authorization' header starting with '{}'", GATEWAY_SECURITY_TOKEN_AUTH_SCHEME);
+ final String presentedToken = authHeader.substring(OFFSET_GATEWAY_TOKEN);
+
+ // validate if the presented token is the same as the gateway token
+ return presentedToken.equals(tenantAware.runAsTenant(controllerSecurityToken.getTenant(), gatewaySecurityTokenKeyConfigRunner))
+ ? authenticatedController(controllerSecurityToken.getTenant(), controllerSecurityToken.getControllerId()) : null;
+ }
+
+ @Override
+ public Logger log() {
+ return log;
+ }
+
+ @Override
+ protected String getTenantConfigurationKey() {
+ return TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticator.java b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticator.java
new file mode 100644
index 000000000..cffece2e3
--- /dev/null
+++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticator.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2025 Contributors to the Eclipse Foundation
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.hawkbit.security.controller;
+
+import java.util.Arrays;
+import java.util.List;
+
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+
+/**
+ * An authenticator which extracts the principal from a request URI and the credential from a request header in a the
+ * {@link ControllerSecurityToken}.
+ */
+@Slf4j
+public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthenticator {
+
+ private static final Logger LOG_SECURITY_AUTH = LoggerFactory.getLogger("server-security.authentication");
+
+ // Example Headers with Cert Information
+ // Clientip: 217.24.201.180
+ // X-Forwarded-Proto: https
+ // X-Ssl-Client-Cn: my.name
+ // X-Ssl-Client-Dn: CN=my.name,CN=O,CN=R,CN=DE,CN=BOSCH,CN=pki,DC=bosch,DC=com
+ // X-Ssl-Client-Hash: 7f:87:cb:b5:9c:e0:c5:0a:1a:a6:57:69:0f:ca:0a:95
+ // X-Ssl-Client-Notafter: Dec 18 08:02:45 2017 GMT
+ // X-Ssl-Client-Notbefore: Dec 18 07:32:45 2014 GMT
+ // X-Ssl-Client-Verify: ok
+ // X-Ssl-Issuer: CN=Bosch-CA1-DE,CN=PKI,DC=Bosch,DC=com
+ // X-Ssl-Issuer-Dn-1: CN=Bosch-CA-DE,CN=PKI,DC=Bosch,DC=com
+ // X-Ssl-Issuer-Hash-1: ae:11:f5:6a:0a:e8:74:50:81:0e:0c:37:ec:c5:22:fc
+ private final String caCommonNameHeader;
+ // the X-Ssl-Issuer-Hash basic header: Contains the x509 fingerprint hash, this
+ // header exists multiple times in the request for all trusted chains.
+ private final String sslIssuerHashBasicHeader;
+
+ private final TenantAware.TenantRunner sslIssuerNameConfigTenantRunner;
+
+ public SecurityHeaderAuthenticator(
+ final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
+ final SystemSecurityContext systemSecurityContext,
+ final String caCommonNameHeader, final String caAuthorityNameHeader) {
+ super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
+ this.caCommonNameHeader = caCommonNameHeader;
+ this.sslIssuerHashBasicHeader = caAuthorityNameHeader;
+ sslIssuerNameConfigTenantRunner = () -> systemSecurityContext.runAsSystem(
+ () -> tenantConfigurationManagement.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class).getValue());
+ }
+
+ @Override
+ public Authentication authenticate(final ControllerSecurityToken controllerSecurityToken) {
+ // retrieve the common name header and the authority name header from the http request and combine them together
+ final String commonNameValue = controllerSecurityToken.getHeader(caCommonNameHeader);
+ if (commonNameValue == null) {
+ log.debug("The request doesn't contain the 'common name' header");
+ return null;
+ }
+ if (!commonNameValue.equals(controllerSecurityToken.getControllerId())) {
+ log.debug("The request contains the 'common name' header but it doesn't match the controller id");
+ return null;
+ }
+
+ if (!isEnabled(controllerSecurityToken)) {
+ log.debug("The gateway header authentication is disabled");
+ return null;
+ }
+
+ final String sslIssuerHashValue = getIssuerHashHeader(
+ controllerSecurityToken,
+ tenantAware.runAsTenant(controllerSecurityToken.getTenant(), sslIssuerNameConfigTenantRunner));
+ if (sslIssuerHashValue == null) {
+ log.debug("The request contains the 'common name' header but trusted hash is not found");
+ return null;
+ }
+ if (log.isTraceEnabled()) {
+ log.debug("Found sslIssuerHash ****, using as credentials for tenant {}", controllerSecurityToken.getTenant());
+ }
+
+ return authenticatedController(controllerSecurityToken.getTenant(), commonNameValue);
+ }
+
+ @Override
+ protected String getTenantConfigurationKey() {
+ return TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
+ }
+
+ @Override
+ public Logger log() {
+ return log;
+ }
+
+ /**
+ * Iterates over the {@link #sslIssuerHashBasicHeader} basic header {@code X-Ssl-Issuer-Hash-%d} and try to find the same hash as known.
+ * It's ok if we find the hash in any the trusted CA chain to accept this request for this tenant.
+ */
+ @SuppressWarnings("java:S2629") // check if debug is enabled is maybe heavier then evaluation
+ private String getIssuerHashHeader(final ControllerSecurityToken controllerSecurityToken, final String knownIssuerHashes) {
+ // there may be several knownIssuerHashes configured for the tenant
+ final List knownHashes = Arrays.stream(knownIssuerHashes.split("[;,]")).map(String::toLowerCase).toList();
+
+ // 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++) {
+ if (knownHashes.contains(foundHash.toLowerCase())) {
+ if (log.isTraceEnabled()) {
+ log.trace("Found matching ssl issuer hash at position {}", iHeader);
+ }
+ return foundHash.toLowerCase();
+ }
+ }
+ LOG_SECURITY_AUTH.debug(
+ "Certificate request but no matching hash found in headers {} for common name {} in request",
+ sslIssuerHashBasicHeader, controllerSecurityToken.getHeader(caCommonNameHeader));
+ return null;
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 000000000..9cfea827b
--- /dev/null
+++ b/hawkbit-ddi/hawkbit-ddi-security/src/main/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticator.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2025 Contributors to the Eclipse Foundation
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.hawkbit.security.controller;
+
+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;
+
+/**
+ * An authenticator which extracts (if enabled through configuration) the possibility to authenticate a target based on
+ * its target security-token with the {@code Authorization} HTTP header.
+ *
+ * {@code Example Header: Authorization: TargetToken 5d8fSD54fdsFG98DDsa.}
+ */
+@Slf4j
+public class SecurityTokenAuthenticator extends Authenticator.AbstractAuthenticator {
+
+ public static final String TARGET_SECURITY_TOKEN_AUTH_SCHEME = "TargetToken ";
+ private static final int OFFSET_TARGET_TOKEN = TARGET_SECURITY_TOKEN_AUTH_SCHEME.length();
+
+ private final ControllerManagement controllerManagement;
+
+ public SecurityTokenAuthenticator(
+ final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
+ final SystemSecurityContext systemSecurityContext,
+ final ControllerManagement controllerManagement) {
+ super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
+ this.controllerManagement = controllerManagement;
+ }
+
+ @Override
+ public Authentication authenticate(final ControllerSecurityToken controllerSecurityToken) {
+ final String authHeader = controllerSecurityToken.getHeader(ControllerSecurityToken.AUTHORIZATION_HEADER);
+ if (authHeader == null) {
+ log.debug("The request doesn't contain the 'authorization' header");
+ return null;
+ } else if (!authHeader.startsWith(TARGET_SECURITY_TOKEN_AUTH_SCHEME)) {
+ log.debug("The request contains the 'authorization' header but it doesn't start with '{}'", TARGET_SECURITY_TOKEN_AUTH_SCHEME);
+ return null;
+ }
+
+ if (!isEnabled(controllerSecurityToken)) {
+ log.debug("The target security token authentication 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
+ ? controllerManagement.get(controllerSecurityToken.getTargetId())
+ : controllerManagement.getByControllerId(controllerSecurityToken.getControllerId()),
+ controllerSecurityToken.getTenant())
+ // validate if the presented token is the same as the one set for the target
+ .filter(target -> presentedToken.equals(target.getSecurityToken()))
+ .map(target -> authenticatedController(controllerSecurityToken.getTenant(), target.getControllerId()))
+ .orElse(null);
+ }
+
+ @Override
+ public Logger log() {
+ return log;
+ }
+
+ @Override
+ protected String getTenantConfigurationKey() {
+ return TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED;
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 000000000..ecea91e65
--- /dev/null
+++ b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/GatewayTokenAuthenticatorTest.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.hawkbit.security.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+import io.qameta.allure.Description;
+import io.qameta.allure.Feature;
+import io.qameta.allure.Story;
+import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
+import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
+import org.eclipse.hawkbit.security.SecurityContextSerializer;
+import org.eclipse.hawkbit.security.SecurityContextTenantAware;
+import org.eclipse.hawkbit.security.SystemSecurityContext;
+import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
+import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@Feature("Unit Tests - Security")
+@Story("Gateway token authentication")
+@ExtendWith(MockitoExtension.class)
+class GatewayTokenAuthenticatorTest {
+
+ private static final String CONTROLLER_ID = "controllerId_gwtoken";
+ private static final String GATEWAY_TOKEN = "test-gw-token";
+ private static final String UNKNOWN_TOKEN = "unknown";
+
+ private static final TenantConfigurationValue CONFIG_VALUE_GW_TOKEN = TenantConfigurationValue
+ . builder().value(GATEWAY_TOKEN).build();
+ private static final TenantConfigurationValue CONFIG_VALUE_ENABLED = TenantConfigurationValue
+ . builder().value(true).build();
+ private static final TenantConfigurationValue CONFIG_VALUE_DISABLED = TenantConfigurationValue
+ . builder().value(false).build();
+
+ private Authenticator authenticator;
+
+ @Mock
+ private TenantConfigurationManagement tenantConfigurationManagementMock;
+ @Mock
+ private UserAuthoritiesResolver authoritiesResolver;
+ @Mock
+ private SecurityContextSerializer securityContextSerializer;
+
+ @BeforeEach
+ void before() {
+ final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver, securityContextSerializer);
+ authenticator = new GatewayTokenAuthenticator(
+ tenantConfigurationManagementMock, tenantAware,
+ new SystemSecurityContext(tenantAware));
+ }
+
+ @Test
+ @Description("Tests successful authentication with gateway token")
+ void testWithGwToken() {
+ final ControllerSecurityToken securityToken = prepareSecurityToken(GATEWAY_TOKEN);
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class))
+ .thenReturn(CONFIG_VALUE_GW_TOKEN);
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_ENABLED);
+
+ assertThat(authenticator.authenticate(securityToken))
+ .isNotNull()
+ .hasFieldOrPropertyWithValue("principal", CONTROLLER_ID);
+ }
+
+ @Test
+ @Description("Tests that if gateway token doesn't match, the authentication fails")
+ void testWithBadGwToken() {
+ final ControllerSecurityToken securityToken = prepareSecurityToken(UNKNOWN_TOKEN);
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class))
+ .thenReturn(CONFIG_VALUE_GW_TOKEN);
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_ENABLED);
+
+ assertThat(authenticator.authenticate(securityToken)).isNull();
+ }
+
+ @Test
+ @Description("Tests that if gateway token miss, the authentication fails")
+ void testWithoutGwToken() {
+ assertThat(authenticator.authenticate(new ControllerSecurityToken("DEFAULT", CONTROLLER_ID))).isNull();
+ }
+
+ @Test
+ @Description("Tests that if disabled, the authentication fails")
+ void testWithGwTokenButDisabled() {
+ final ControllerSecurityToken securityToken = prepareSecurityToken(GATEWAY_TOKEN);
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_DISABLED);
+
+ assertThat(authenticator.authenticate(securityToken)).isNull();
+ }
+
+ private static ControllerSecurityToken prepareSecurityToken(final String gwToken) {
+ final ControllerSecurityToken securityToken = new ControllerSecurityToken("DEFAULT", CONTROLLER_ID);
+ securityToken.putHeader(ControllerSecurityToken.AUTHORIZATION_HEADER, GatewayTokenAuthenticator.GATEWAY_SECURITY_TOKEN_AUTH_SCHEME + gwToken);
+ return securityToken;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-security/hawkbit-security-controller/src/test/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityHeaderFilterTest.java b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticatorTest.java
similarity index 53%
rename from hawkbit-security/hawkbit-security-controller/src/test/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityHeaderFilterTest.java
rename to hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticatorTest.java
index 792f46161..57a585bbf 100644
--- a/hawkbit-security/hawkbit-security-controller/src/test/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityHeaderFilterTest.java
+++ b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityHeaderAuthenticatorTest.java
@@ -12,8 +12,6 @@ package org.eclipse.hawkbit.security.controller;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
-import java.util.Collection;
-
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@@ -31,9 +29,9 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@Feature("Unit Tests - Security")
-@Story("Issuer hash based authentication")
+@Story("Security header authenticator")
@ExtendWith(MockitoExtension.class)
-class ControllerPreAuthenticatedSecurityHeaderFilterTest {
+class SecurityHeaderAuthenticatorTest {
private static final String CA_COMMON_NAME = "ca-cn";
private static final String CA_COMMON_NAME_VALUE = "box1";
@@ -49,11 +47,14 @@ class ControllerPreAuthenticatedSecurityHeaderFilterTest {
private static final TenantConfigurationValue CONFIG_VALUE_SINGLE_HASH = TenantConfigurationValue
. builder().value(SINGLE_HASH).build();
-
private static final TenantConfigurationValue CONFIG_VALUE_MULTI_HASH = TenantConfigurationValue
. builder().value(MULTI_HASH).build();
+ private static final TenantConfigurationValue CONFIG_VALUE_ENABLED = TenantConfigurationValue
+ . builder().value(true).build();
+ private static final TenantConfigurationValue CONFIG_VALUE_DISABLED = TenantConfigurationValue
+ . builder().value(false).build();
- private ControllerPreAuthenticatedSecurityHeaderFilter underTest;
+ private Authenticator authenticator;
@Mock
private TenantConfigurationManagement tenantConfigurationManagementMock;
@@ -65,72 +66,88 @@ class ControllerPreAuthenticatedSecurityHeaderFilterTest {
@BeforeEach
void before() {
final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver, securityContextSerializer);
- underTest = new ControllerPreAuthenticatedSecurityHeaderFilter(
- CA_COMMON_NAME, "X-Ssl-Issuer-Hash-%d",
- tenantConfigurationManagementMock, tenantAware, new SystemSecurityContext(tenantAware));
+ authenticator = new SecurityHeaderAuthenticator(
+ tenantConfigurationManagementMock, tenantAware,
+ new SystemSecurityContext(tenantAware), CA_COMMON_NAME, "X-Ssl-Issuer-Hash-%d"
+ );
}
@Test
- @Description("Tests the filter for issuer hash based authentication with a single known hash")
- void testIssuerHashBasedAuthenticationWithSingleKnownHash() {
+ @Description("Tests successful authentication with multiple a single hashes")
+ void testWithSingleKnownHash() {
final ControllerSecurityToken securityToken = prepareSecurityToken(SINGLE_HASH);
- // use single known hash
when(tenantConfigurationManagementMock.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_SINGLE_HASH);
- assertThat(underTest.getPreAuthenticatedPrincipal(securityToken)).isNotNull();
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_ENABLED);
+
+ assertThat(authenticator.authenticate(securityToken))
+ .isNotNull()
+ .hasFieldOrPropertyWithValue("principal", CA_COMMON_NAME_VALUE);
}
@Test
- @Description("Tests the filter for issuer hash based authentication with multiple known hashes")
- void testIssuerHashBasedAuthenticationWithMultipleKnownHashes() {
- // use multiple known hashes
+ @Description("Tests successful authentication with multiple hashes")
+ void testWithMultipleKnownHashes() {
when(tenantConfigurationManagementMock.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_MULTI_HASH);
- assertThat(underTest.getPreAuthenticatedPrincipal(prepareSecurityToken(SINGLE_HASH))).isNotNull();
- assertThat(underTest.getPreAuthenticatedPrincipal(prepareSecurityToken(SECOND_HASH))).isNotNull();
- assertThat(underTest.getPreAuthenticatedPrincipal(prepareSecurityToken(THIRD_HASH))).isNotNull();
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_ENABLED);
+
+ assertThat(authenticator.authenticate(prepareSecurityToken(SINGLE_HASH)))
+ .isNotNull()
+ .hasFieldOrPropertyWithValue("principal", CA_COMMON_NAME_VALUE);
+ assertThat(authenticator.authenticate(prepareSecurityToken(SECOND_HASH)))
+ .isNotNull()
+ .hasFieldOrPropertyWithValue("principal", CA_COMMON_NAME_VALUE);
+ assertThat(authenticator.authenticate(prepareSecurityToken(THIRD_HASH)))
+ .isNotNull()
+ .hasFieldOrPropertyWithValue("principal", CA_COMMON_NAME_VALUE);
}
@Test
- @Description("Tests the filter for issuer hash based authentication with unknown hash")
- void testIssuerHashBasedAuthenticationWithUnknownHash() {
+ @Description("Tests that if the hash is unknown, the authentication fails")
+ void testWithUnknownHash() {
final ControllerSecurityToken securityToken = prepareSecurityToken(UNKNOWN_HASH);
- // use single known hash
when(tenantConfigurationManagementMock.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_MULTI_HASH);
- assertThat(underTest.getPreAuthenticatedPrincipal(securityToken)).isNull();
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_ENABLED);
+
+ assertThat(authenticator.authenticate(securityToken)).isNull();
}
@Test
- @Description("Tests different values for issuer hash header and inspects the credentials")
- void useDifferentValuesForIssuerHashHeader() {
- final ControllerSecurityToken securityToken1 = prepareSecurityToken(SINGLE_HASH);
- final ControllerSecurityToken securityToken2 = prepareSecurityToken(SECOND_HASH);
+ @Description("Tests that if CN doesn't match the CN in the security token, the authentication fails")
+ void testWithNonMatchingCN() {
+ final ControllerSecurityToken securityToken = new ControllerSecurityToken("DEFAULT", "otherControllerID");
+ securityToken.putHeader(CA_COMMON_NAME, CA_COMMON_NAME_VALUE);
+ securityToken.putHeader(X_SSL_ISSUER_HASH_1, SINGLE_HASH);
- final HeaderAuthentication expected1 = new HeaderAuthentication(CA_COMMON_NAME_VALUE, SINGLE_HASH);
- final HeaderAuthentication expected2 = new HeaderAuthentication(CA_COMMON_NAME_VALUE, SECOND_HASH);
+ assertThat(authenticator.authenticate(securityToken)).isNull();
+ }
+ @Test
+ @Description("Tests that if the hash miss, the authentication fails")
+ void testWithoutHash() {
+ assertThat(authenticator.authenticate(new ControllerSecurityToken("DEFAULT", CA_COMMON_NAME_VALUE))).isNull();
+ }
+
+ @Test
+ @Description("Tests that if disabled, the authentication fails")
+ void testWithSingleKnownHashButDisabled() {
+ final ControllerSecurityToken securityToken = prepareSecurityToken(SINGLE_HASH);
when(tenantConfigurationManagementMock.getConfigurationValue(
- TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class))
- .thenReturn(CONFIG_VALUE_MULTI_HASH);
-
- final Collection credentials1 = (Collection) underTest
- .getPreAuthenticatedCredentials(securityToken1);
- final Collection credentials2 = (Collection) underTest
- .getPreAuthenticatedCredentials(securityToken2);
-
- final Object principal1 = underTest.getPreAuthenticatedPrincipal(securityToken1);
- final Object principal2 = underTest.getPreAuthenticatedPrincipal(securityToken2);
-
- assertThat(credentials1).contains(expected1);
- assertThat(credentials2).contains(expected2);
-
- assertThat(expected1).as("hash1 expected in principal!").isEqualTo(principal1);
- assertThat(expected2).as("hash2 expected in principal!").isEqualTo(principal2);
+ TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_DISABLED);
+ assertThat(authenticator.authenticate(securityToken)).isNull();
}
private static ControllerSecurityToken prepareSecurityToken(final String issuerHashHeaderValue) {
@@ -139,5 +156,4 @@ class ControllerPreAuthenticatedSecurityHeaderFilterTest {
securityToken.putHeader(X_SSL_ISSUER_HASH_1, issuerHashHeaderValue);
return securityToken;
}
-
-}
+}
\ No newline at end of file
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
new file mode 100644
index 000000000..12c3de01c
--- /dev/null
+++ b/hawkbit-ddi/hawkbit-ddi-security/src/test/java/org/eclipse/hawkbit/security/controller/SecurityTokenAuthenticatorTest.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2015 Bosch Software Innovations GmbH and others
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.hawkbit.security.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+import java.util.Optional;
+
+import io.qameta.allure.Description;
+import io.qameta.allure.Feature;
+import io.qameta.allure.Story;
+import org.eclipse.hawkbit.repository.ControllerManagement;
+import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
+import org.eclipse.hawkbit.repository.model.Target;
+import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
+import org.eclipse.hawkbit.security.SecurityContextSerializer;
+import org.eclipse.hawkbit.security.SecurityContextTenantAware;
+import org.eclipse.hawkbit.security.SystemSecurityContext;
+import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
+import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@Feature("Unit Tests - Security")
+@Story("Gateway token authentication")
+@ExtendWith(MockitoExtension.class)
+class SecurityTokenAuthenticatorTest {
+
+ private static final String CONTROLLER_ID = "controllerId_gwtoken";
+ private static final String SECURITY_TOKEN = "test-sec-token";
+ private static final String UNKNOWN_TOKEN = "unknown";
+
+ private static final TenantConfigurationValue CONFIG_VALUE_GW_TOKEN = TenantConfigurationValue
+ . builder().value(SECURITY_TOKEN).build();
+ private static final TenantConfigurationValue CONFIG_VALUE_ENABLED = TenantConfigurationValue
+ . builder().value(true).build();
+ private static final TenantConfigurationValue CONFIG_VALUE_DISABLED = TenantConfigurationValue
+ . builder().value(false).build();
+
+ private Authenticator authenticator;
+
+ @Mock
+ private TenantConfigurationManagement tenantConfigurationManagementMock;
+ @Mock
+ private ControllerManagement controllerManagementMock;
+ @Mock
+ private UserAuthoritiesResolver authoritiesResolver;
+ @Mock
+ private SecurityContextSerializer securityContextSerializer;
+
+ @BeforeEach
+ void before() {
+ final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver, securityContextSerializer);
+ authenticator = new SecurityTokenAuthenticator(
+ tenantConfigurationManagementMock, tenantAware,
+ new SystemSecurityContext(tenantAware), controllerManagementMock);
+ }
+
+ @Test
+ @Description("Tests successful authentication with gateway token")
+ void testWithSecToken() {
+ final ControllerSecurityToken securityToken = prepareSecurityToken(SECURITY_TOKEN);
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_ENABLED);
+
+ final Target target = Mockito.mock(Target.class);
+ when(target.getControllerId()).thenReturn(CONTROLLER_ID);
+ when(target.getSecurityToken()).thenReturn(SECURITY_TOKEN);
+ when(controllerManagementMock.getByControllerId(CONTROLLER_ID)).thenReturn(Optional.of(target));
+
+ assertThat(authenticator.authenticate(securityToken))
+ .isNotNull()
+ .hasFieldOrPropertyWithValue("principal", CONTROLLER_ID);
+ }
+
+ @Test
+ @Description("Tests that if gateway token doesn't match, the authentication fails")
+ void testWithBadSecToken() {
+ final ControllerSecurityToken securityToken = prepareSecurityToken(UNKNOWN_TOKEN);
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_ENABLED);
+
+ assertThat(authenticator.authenticate(securityToken)).isNull();
+ }
+
+ @Test
+ @Description("Tests that if gateway token miss, the authentication fails")
+ void testWithoutSecToken() {
+ assertThat(authenticator.authenticate(new ControllerSecurityToken("DEFAULT", CONTROLLER_ID))).isNull();
+ }
+
+ @Test
+ @Description("Tests that if disabled, the authentication fails")
+ void testWithSecTokenButDisabled() {
+ final ControllerSecurityToken securityToken = prepareSecurityToken(SECURITY_TOKEN);
+ when(tenantConfigurationManagementMock.getConfigurationValue(
+ TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED, Boolean.class))
+ .thenReturn(CONFIG_VALUE_DISABLED);
+
+ assertThat(authenticator.authenticate(securityToken)).isNull();
+ }
+
+ private static ControllerSecurityToken prepareSecurityToken(final String secToken) {
+ final ControllerSecurityToken securityToken = new ControllerSecurityToken("DEFAULT", CONTROLLER_ID);
+ securityToken.putHeader(ControllerSecurityToken.AUTHORIZATION_HEADER, SecurityTokenAuthenticator.TARGET_SECURITY_TOKEN_AUTH_SCHEME + secToken);
+ return securityToken;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-ddi/hawkbit-ddi-starter/pom.xml b/hawkbit-ddi/hawkbit-ddi-starter/pom.xml
index c6fb73415..17988e48a 100644
--- a/hawkbit-ddi/hawkbit-ddi-starter/pom.xml
+++ b/hawkbit-ddi/hawkbit-ddi-starter/pom.xml
@@ -25,7 +25,7 @@
org.eclipse.hawkbit
- hawkbit-security-controller
+ hawkbit-ddi-security
${project.version}
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 457eef9a1..7474e1ef0 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,10 +12,6 @@ package org.eclipse.hawkbit.autoconfigure.ddi;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
-import org.eclipse.hawkbit.autoconfigure.ddi.security.ControllerTenantAwareAuthenticationDetailsSource;
-import org.eclipse.hawkbit.autoconfigure.ddi.security.HttpControllerPreAuthenticateSecurityTokenFilter;
-import org.eclipse.hawkbit.autoconfigure.ddi.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter;
-import org.eclipse.hawkbit.autoconfigure.ddi.security.HttpControllerPreAuthenticatedSecurityHeaderFilter;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
@@ -25,7 +21,15 @@ 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.Authenticator;
+import org.eclipse.hawkbit.security.controller.ControllerSecurityToken;
+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.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
+import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -33,11 +37,12 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
-import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.Authentication;
import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.access.intercept.AuthorizationFilter;
/**
* Security configuration for the hawkBit server DDI download interface.
@@ -89,8 +94,6 @@ class ControllerDownloadSecurityConfiguration {
@Bean
@Order(300) // higher priority than HawkBit DDI security, so that the DDI DL security is applied first
protected SecurityFilterChain filterChainDDIDL(final HttpSecurity http) throws Exception {
- final AuthenticationManager authenticationManager = ControllerSecurityConfiguration.setAuthenticationManager(http, ddiSecurityConfiguration);
-
http
.securityMatcher(DDI_DL_ANT_MATCHER)
.csrf(AbstractHttpConfigurer::disable);
@@ -99,34 +102,27 @@ class ControllerDownloadSecurityConfiguration {
http.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure());
}
- final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
-
- final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
- ddiSecurityConfiguration.getRp().getCnHeader(),
- ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(), tenantConfigurationManagement,
- tenantAware, systemSecurityContext);
- securityHeaderFilter.setAuthenticationManager(authenticationManager);
- securityHeaderFilter.setCheckForPrincipalChanges(true);
- securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
- tenantConfigurationManagement, tenantAware, controllerManagement, systemSecurityContext);
- securityTokenFilter.setAuthenticationManager(authenticationManager);
- securityTokenFilter.setCheckForPrincipalChanges(true);
- securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
- tenantConfigurationManagement, tenantAware, systemSecurityContext);
- gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager);
- gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
- gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
http
.authorizeHttpRequests(amrmRegistry -> amrmRegistry.anyRequest().authenticated())
.anonymous(AbstractHttpConfigurer::disable)
- .addFilter(securityHeaderFilter)
- .addFilter(securityTokenFilter)
- .addFilter(gatewaySecurityTokenFilter)
+ .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.AbstractAuthenticationFilter(
+ new AnonymousAuthenticator(
+ tenantConfigurationManagement, tenantAware, systemSecurityContext),
+ ddiSecurityConfiguration) {}, AuthorizationFilter.class)
.exceptionHandling(configurer -> configurer.authenticationEntryPoint(
(request, response, authException) -> response.setStatus(HttpStatus.UNAUTHORIZED.value())))
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
@@ -135,4 +131,29 @@ class ControllerDownloadSecurityConfiguration {
return http.build();
}
+
+ @Slf4j
+ private static class AnonymousAuthenticator extends Authenticator.AbstractAuthenticator {
+
+ protected AnonymousAuthenticator(
+ final TenantConfigurationManagement tenantConfigurationManagement,
+ final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
+ super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
+ }
+
+ @Override
+ public Authentication authenticate(final ControllerSecurityToken controllerSecurityToken) {
+ return isEnabled(controllerSecurityToken) ? authenticatedController(controllerSecurityToken.getTenant(), null) : null;
+ }
+
+ @Override
+ protected String getTenantConfigurationKey() {
+ return TenantConfigurationProperties.TenantConfigurationKey.ANONYMOUS_DOWNLOAD_MODE_ENABLED;
+ }
+
+ @Override
+ public Logger log() {
+ return log;
+ }
+ }
}
\ No newline at end of file
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 76481941c..cf7179d0c 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,10 +12,6 @@ package org.eclipse.hawkbit.autoconfigure.ddi;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
-import org.eclipse.hawkbit.autoconfigure.ddi.security.ControllerTenantAwareAuthenticationDetailsSource;
-import org.eclipse.hawkbit.autoconfigure.ddi.security.HttpControllerPreAuthenticateSecurityTokenFilter;
-import org.eclipse.hawkbit.autoconfigure.ddi.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter;
-import org.eclipse.hawkbit.autoconfigure.ddi.security.HttpControllerPreAuthenticatedSecurityHeaderFilter;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
@@ -25,7 +21,10 @@ 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.PreAuthTokenSourceTrustAuthenticationProvider;
+import org.eclipse.hawkbit.security.controller.AuthenticationFilters;
+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.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -34,13 +33,12 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.access.intercept.AuthorizationFilter;
/**
* Security configuration for the hawkBit server DDI interface.
@@ -93,8 +91,6 @@ class ControllerSecurityConfiguration {
@Bean
@Order(301)
protected SecurityFilterChain filterChainDDI(final HttpSecurity http) throws Exception {
- final AuthenticationManager authenticationManager = setAuthenticationManager(http, ddiSecurityConfiguration);
-
http
.securityMatcher(DDI_ANT_MATCHERS)
.csrf(AbstractHttpConfigurer::disable);
@@ -103,34 +99,22 @@ class ControllerSecurityConfiguration {
http.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure());
}
- final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
-
- final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
- ddiSecurityConfiguration.getRp().getCnHeader(),
- ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(), tenantConfigurationManagement,
- tenantAware, systemSecurityContext);
- securityHeaderFilter.setAuthenticationManager(authenticationManager);
- securityHeaderFilter.setCheckForPrincipalChanges(true);
- securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
- tenantConfigurationManagement, tenantAware, controllerManagement, systemSecurityContext);
- securityTokenFilter.setAuthenticationManager(authenticationManager);
- securityTokenFilter.setCheckForPrincipalChanges(true);
- securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
- tenantConfigurationManagement, tenantAware, systemSecurityContext);
- gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager);
- gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
- gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
http
.authorizeHttpRequests(amrmRegistry -> amrmRegistry.anyRequest().authenticated())
.anonymous(AbstractHttpConfigurer::disable)
- .addFilter(securityHeaderFilter)
- .addFilter(securityTokenFilter)
- .addFilter(gatewaySecurityTokenFilter)
+ .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)
.exceptionHandling(configurer -> configurer.authenticationEntryPoint(
(request, response, authException) -> response.setStatus(HttpStatus.UNAUTHORIZED.value())))
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
@@ -139,17 +123,4 @@ class ControllerSecurityConfiguration {
return http.build();
}
-
- static AuthenticationManager setAuthenticationManager(final HttpSecurity http, final DdiSecurityProperties ddiSecurityConfiguration)
- throws Exception {
- // configure authentication manager
- final AuthenticationManager authenticationManager =
- http
- .getSharedObject(AuthenticationManagerBuilder.class)
- .authenticationProvider(
- new PreAuthTokenSourceTrustAuthenticationProvider(ddiSecurityConfiguration.getRp().getTrustedIPs()))
- .build();
- http.authenticationManager(authenticationManager);
- return authenticationManager;
- }
}
\ No newline at end of file
diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/AbstractHttpControllerAuthenticationFilter.java b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/AbstractHttpControllerAuthenticationFilter.java
deleted file mode 100644
index 1568848b5..000000000
--- a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/AbstractHttpControllerAuthenticationFilter.java
+++ /dev/null
@@ -1,182 +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.autoconfigure.ddi.security;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.ServletRequest;
-import jakarta.servlet.ServletResponse;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
-import org.eclipse.hawkbit.security.SystemSecurityContext;
-import org.eclipse.hawkbit.security.controller.ControllerSecurityToken;
-import org.eclipse.hawkbit.security.controller.PreAuthenticationFilter;
-import org.eclipse.hawkbit.tenancy.TenantAware;
-import org.eclipse.hawkbit.util.UrlUtils;
-import org.slf4j.Logger;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
-import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
-import org.springframework.util.AntPathMatcher;
-
-/**
- * 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 security checks
- * based on this information.
- */
-public abstract class AbstractHttpControllerAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
-
- protected TenantConfigurationManagement tenantConfigurationManagement;
- protected TenantAware tenantAware;
- protected SystemSecurityContext systemSecurityContext;
-
- private static final String TENANT_PLACE_HOLDER = "tenant";
- private static final String CONTROLLER_ID_PLACE_HOLDER = "controllerId";
- /**
- * requestURIPathPattern the request URI path pattern in ANT style
- * containing the placeholder key for retrieving the principal from the URI
- * request. e.g."/{tenant}/controller/v1/{controllerId}
- */
- private static final String CONTROLLER_REQUEST_ANT_PATTERN = "/{" + TENANT_PLACE_HOLDER + "}/controller/v1" +
- "/{" + CONTROLLER_ID_PLACE_HOLDER + "}/**";
- private static final String CONTROLLER_DL_REQUEST_ANT_PATTERN = "/{" + TENANT_PLACE_HOLDER + "}/controller/artifacts/v1/**";
-
- private final AntPathMatcher pathExtractor;
- private PreAuthenticationFilter abstractControllerAuthenticationFilter;
-
- /**
- * Constructor for subclasses.
- *
- * @param tenantConfigurationManagement the tenant configuration service
- * @param tenantAware the tenant aware service
- * @param systemSecurityContext the system security context
- */
- protected AbstractHttpControllerAuthenticationFilter(
- final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
- final SystemSecurityContext systemSecurityContext) {
- this.tenantConfigurationManagement = tenantConfigurationManagement;
- this.tenantAware = tenantAware;
- this.systemSecurityContext = systemSecurityContext;
- pathExtractor = new AntPathMatcher();
- }
-
- @Override
- public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
- throws IOException, ServletException {
- if (SecurityContextHolder.getContext().getAuthentication() != null) {
- log().trace("Request is already authenticated. Skip filter");
- chain.doFilter(request, response);
- return;
- }
-
- if (!(request instanceof HttpServletRequest)) {
- chain.doFilter(request, response);
- return;
- }
-
- final ControllerSecurityToken securityToken = createTenantSecurityTokenVariables((HttpServletRequest) request);
- if (securityToken == null) {
- chain.doFilter(request, response);
- return;
- }
-
- abstractControllerAuthenticationFilter = createControllerAuthenticationFilter();
- if (abstractControllerAuthenticationFilter.isEnable(securityToken)) {
- super.doFilter(request, response, chain);
- } else {
- log().debug("Filter is disabled for the tenant {}", securityToken.getTenant());
- chain.doFilter(request, response);
- }
- }
-
- @Override
- protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response,
- final Authentication authResult) throws IOException, ServletException {
- final Collection authorities = new ArrayList<>();
- authorities.addAll(authResult.getAuthorities());
- authorities.addAll(abstractControllerAuthenticationFilter.getSuccessfulAuthenticationAuthorities());
- final PreAuthenticatedAuthenticationToken authTokenWithGrantedAuthorities = new PreAuthenticatedAuthenticationToken(
- authResult.getPrincipal(), authResult.getCredentials(), authorities);
- authTokenWithGrantedAuthorities.setDetails(authResult.getDetails());
- super.successfulAuthentication(request, response, authTokenWithGrantedAuthorities);
- }
-
- @Override
- protected Object getPreAuthenticatedPrincipal(final HttpServletRequest request) {
- final ControllerSecurityToken securityToken = createTenantSecurityTokenVariables(request);
- if (securityToken == null) {
- return null;
- }
- return abstractControllerAuthenticationFilter.getPreAuthenticatedPrincipal(securityToken);
- }
-
- @Override
- protected Object getPreAuthenticatedCredentials(final HttpServletRequest request) {
- final ControllerSecurityToken securityToken = createTenantSecurityTokenVariables(request);
- if (securityToken == null) {
- return null;
- }
- return abstractControllerAuthenticationFilter.getPreAuthenticatedCredentials(securityToken);
- }
-
- protected abstract PreAuthenticationFilter createControllerAuthenticationFilter();
-
- protected abstract Logger log();
-
- /**
- * Extracts tenant and controllerId from the request URI as path variables.
- *
- * @param request the Http request to extract the path variables.
- * @return the extracted {@link ControllerSecurityToken} or {@code null} if the
- * request does not match the pattern and no variables could be
- * extracted
- */
- protected ControllerSecurityToken createTenantSecurityTokenVariables(final HttpServletRequest request) {
- final String requestURI = request.getRequestURI();
-
- if (pathExtractor.match(request.getContextPath() + CONTROLLER_REQUEST_ANT_PATTERN, requestURI)) {
- 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));
- log().trace("Parsed tenant {} and controllerId {} from path request {}", tenant, controllerId, requestURI);
- return createTenantSecurityTokenVariables(request, tenant, controllerId);
- } else if (pathExtractor.match(request.getContextPath() + CONTROLLER_DL_REQUEST_ANT_PATTERN, requestURI)) {
- log().debug("retrieving path variables from URI request {}", requestURI);
- final Map extractUriTemplateVariables = pathExtractor.extractUriTemplateVariables(
- request.getContextPath() + CONTROLLER_DL_REQUEST_ANT_PATTERN, requestURI);
- final String tenant = UrlUtils.decodeUriValue(extractUriTemplateVariables.get(TENANT_PLACE_HOLDER));
- log().trace("Parsed tenant {} from path request {}", tenant, requestURI);
- return createTenantSecurityTokenVariables(request, tenant, "anonymous");
- } else {
- log().trace("request {} does not match the path pattern {}, request gets ignored", requestURI,
- CONTROLLER_REQUEST_ANT_PATTERN);
- return null;
- }
- }
-
- private ControllerSecurityToken createTenantSecurityTokenVariables(final HttpServletRequest request,
- final String tenant, final String controllerId) {
- final ControllerSecurityToken securityToken = new ControllerSecurityToken(tenant, null, controllerId, null);
- Collections.list(request.getHeaderNames()).forEach(header -> securityToken.putHeader(header, request.getHeader(header)));
- return securityToken;
- }
-}
\ No newline at end of file
diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/ControllerTenantAwareAuthenticationDetailsSource.java b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/ControllerTenantAwareAuthenticationDetailsSource.java
deleted file mode 100644
index a34dc730b..000000000
--- a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/ControllerTenantAwareAuthenticationDetailsSource.java
+++ /dev/null
@@ -1,65 +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.autoconfigure.ddi.security;
-
-import java.util.Map;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import lombok.extern.slf4j.Slf4j;
-import org.eclipse.hawkbit.security.controller.TenantAwareWebAuthenticationDetails;
-import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
-import org.eclipse.hawkbit.util.UrlUtils;
-import org.springframework.security.authentication.AuthenticationDetailsSource;
-import org.springframework.util.AntPathMatcher;
-
-/**
- * An {@link AuthenticationDetailsSource} implementation which retrieves the
- * tenant from a request pattern {@link #TENANT_AWARE_CONTROLLER_PATTERN} and
- * stores the retrieved tenant in the {@link TenantAwareAuthenticationDetails}.
- */
-@Slf4j
-public class ControllerTenantAwareAuthenticationDetailsSource
- implements AuthenticationDetailsSource {
-
- private static final String TENANT_AWARE_CONTROLLER_PATTERN = "/{tenant}/controller/**";
- private static final String TENANT_PLACE_HOLDER = "tenant";
- private final AntPathMatcher pathExtractor;
-
- /**
- * Constructor.
- */
- public ControllerTenantAwareAuthenticationDetailsSource() {
- pathExtractor = new AntPathMatcher();
- }
-
- @Override
- public TenantAwareAuthenticationDetails buildDetails(final HttpServletRequest request) {
- return new TenantAwareWebAuthenticationDetails(getTenantFromRequestUri(request), request.getRemoteAddr(), true);
- }
-
- private String getTenantFromRequestUri(final HttpServletRequest request) {
- final String requestURI = request.getRequestURI();
- log.debug("retrieving tenant from URI request {}", requestURI);
- final String requestPathPattern = request.getContextPath() + TENANT_AWARE_CONTROLLER_PATTERN;
- if (!pathExtractor.match(requestPathPattern, requestURI)) {
- log.info("Controller request not matching tenant aware request pattern requestpath: {}, pattern {}",
- requestURI, TENANT_AWARE_CONTROLLER_PATTERN);
- return null;
- }
- final Map extractUriTemplateVariables = pathExtractor
- .extractUriTemplateVariables(requestPathPattern, requestURI);
- if (log.isTraceEnabled()) {
- log.trace("Parsed path variables {} using tenant {}", extractUriTemplateVariables,
- extractUriTemplateVariables.get(TENANT_PLACE_HOLDER));
- }
- return UrlUtils.decodeUriValue(extractUriTemplateVariables.get(TENANT_PLACE_HOLDER));
- }
-}
diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticateSecurityTokenFilter.java b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticateSecurityTokenFilter.java
deleted file mode 100644
index 4622c085c..000000000
--- a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticateSecurityTokenFilter.java
+++ /dev/null
@@ -1,67 +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.autoconfigure.ddi.security;
-
-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.security.controller.ControllerPreAuthenticatedSecurityTokenFilter;
-import org.eclipse.hawkbit.security.controller.PreAuthenticationFilter;
-import org.eclipse.hawkbit.tenancy.TenantAware;
-import org.slf4j.Logger;
-
-/**
- * An pre-authenticated processing filter which extracts (if enabled through
- * configuration) the possibility to authenticate a target based on its target
- * security-token with the {@code Authorization} HTTP header.
- * {@code Example Header: Authorization: TargetToken
- * 5d8fSD54fdsFG98DDsa.}
- *
- * The {@code Authorization} header is a HTTP standard and reverse proxy or
- * other proxies will keep the Authorization headers untouched instead of maybe
- * custom headers which have then weird side-effects. Furthermore frameworks are
- * aware of the sensitivity of the Authorization header and do not log it and
- * store it somewhere.
- */
-@Slf4j
-public class HttpControllerPreAuthenticateSecurityTokenFilter extends AbstractHttpControllerAuthenticationFilter {
-
- private final ControllerManagement controllerManagement;
-
- /**
- * Constructor.
- *
- * @param tenantConfigurationManagement the system management service to retrieve configuration
- * properties
- * @param tenantAware the tenant aware service to get configuration for the specific
- * tenant
- * @param controllerManagement the controller management to retrieve the specific target
- * security token to verify
- * @param systemSecurityContext the system security context
- */
- public HttpControllerPreAuthenticateSecurityTokenFilter(
- final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
- final ControllerManagement controllerManagement, final SystemSecurityContext systemSecurityContext) {
- super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
- this.controllerManagement = controllerManagement;
- }
-
- @Override
- protected PreAuthenticationFilter createControllerAuthenticationFilter() {
- return new ControllerPreAuthenticatedSecurityTokenFilter(tenantConfigurationManagement, controllerManagement,
- tenantAware, systemSecurityContext);
- }
-
- @Override
- protected Logger log() {
- return log;
- }
-}
\ No newline at end of file
diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticatedGatewaySecurityTokenFilter.java b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticatedGatewaySecurityTokenFilter.java
deleted file mode 100644
index 22f51d4b0..000000000
--- a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticatedGatewaySecurityTokenFilter.java
+++ /dev/null
@@ -1,56 +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.autoconfigure.ddi.security;
-
-import lombok.extern.slf4j.Slf4j;
-import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
-import org.eclipse.hawkbit.security.SystemSecurityContext;
-import org.eclipse.hawkbit.security.controller.ControllerPreAuthenticatedGatewaySecurityTokenFilter;
-import org.eclipse.hawkbit.security.controller.PreAuthenticationFilter;
-import org.eclipse.hawkbit.tenancy.TenantAware;
-import org.slf4j.Logger;
-
-/**
- * Extract the {@code Authorization} header is a HTTP standard and reverse proxy
- * or other proxies will keep the Authorization headers untouched instead of
- * maybe custom headers which have then weird side-effects. Furthermore
- * frameworks are aware of the sensitivity of the Authorization header and do
- * not log it and store it somewhere.
- */
-@Slf4j
-public class HttpControllerPreAuthenticatedGatewaySecurityTokenFilter
- extends AbstractHttpControllerAuthenticationFilter {
-
- /**
- * Constructor.
- *
- * @param tenantConfigurationManagement the system management service to retrieve configuration
- * properties
- * @param tenantAware the tenant aware service to get configuration for the specific
- * tenant
- * @param systemSecurityContext the system security context
- */
- public HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
- final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
- final SystemSecurityContext systemSecurityContext) {
- super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
- }
-
- @Override
- protected PreAuthenticationFilter createControllerAuthenticationFilter() {
- return new ControllerPreAuthenticatedGatewaySecurityTokenFilter(tenantConfigurationManagement, tenantAware,
- systemSecurityContext);
- }
-
- @Override
- protected Logger log() {
- return log;
- }
-}
\ No newline at end of file
diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticatedSecurityHeaderFilter.java b/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticatedSecurityHeaderFilter.java
deleted file mode 100644
index 52a13cb1c..000000000
--- a/hawkbit-ddi/hawkbit-ddi-starter/src/main/java/org/eclipse/hawkbit/autoconfigure/ddi/security/HttpControllerPreAuthenticatedSecurityHeaderFilter.java
+++ /dev/null
@@ -1,66 +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.autoconfigure.ddi.security;
-
-import lombok.extern.slf4j.Slf4j;
-import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
-import org.eclipse.hawkbit.security.SystemSecurityContext;
-import org.eclipse.hawkbit.security.controller.ControllerPreAuthenticatedSecurityHeaderFilter;
-import org.eclipse.hawkbit.security.controller.PreAuthenticationFilter;
-import org.eclipse.hawkbit.tenancy.TenantAware;
-import org.slf4j.Logger;
-
-/**
- * An pre-authenticated processing filter which extracts the principal from a
- * request URI and the credential from a request header.
- */
-@Slf4j
-public class HttpControllerPreAuthenticatedSecurityHeaderFilter extends AbstractHttpControllerAuthenticationFilter {
-
- private final String caCommonNameHeader;
- private final String caAuthorityNameHeader;
-
- /**
- * Creates a new {@link org.eclipse.hawkbit.security.ControllerPreAuthenticatedSecurityHeaderFilter}, in
- * case the HTTP request matches the given pattern the principal is parsed
- * from the HTTP request with the given URI pattern, in case the URI pattern
- * does not match the current request then only the existence of the
- * configured header field is checked.
- *
- * @param caCommonNameHeader the http-header which holds the common-name of the certificate
- * @param caAuthorityNameHeader the http-header which holds the ca-authority name of the
- * certificate
- * @param tenantConfigurationManagement the tenant configuration management service to retrieve
- * configuration properties to check if the header authentication
- * is enabled for this tenant
- * @param tenantAware the tenant aware service to get configuration for the specific
- * tenant
- * @param systemSecurityContext the system security context
- */
- public HttpControllerPreAuthenticatedSecurityHeaderFilter(final String caCommonNameHeader,
- final String caAuthorityNameHeader, final TenantConfigurationManagement tenantConfigurationManagement,
- final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
- super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
- this.caCommonNameHeader = caCommonNameHeader;
- this.caAuthorityNameHeader = caAuthorityNameHeader;
- }
-
- @Override
- protected PreAuthenticationFilter createControllerAuthenticationFilter() {
- return new ControllerPreAuthenticatedSecurityHeaderFilter(
- caCommonNameHeader, caAuthorityNameHeader,
- tenantConfigurationManagement, tenantAware, systemSecurityContext);
- }
-
- @Override
- protected Logger log() {
- return log;
- }
-}
\ No newline at end of file
diff --git a/hawkbit-ddi/hawkbit-ddi-starter/src/test/java/org/eclipse/hawkbit/autoconfigure/ddi/security/PreAuthTokenSourceTrustAuthenticationProviderTest.java b/hawkbit-ddi/hawkbit-ddi-starter/src/test/java/org/eclipse/hawkbit/autoconfigure/ddi/security/PreAuthTokenSourceTrustAuthenticationProviderTest.java
deleted file mode 100644
index 8a3f17199..000000000
--- a/hawkbit-ddi/hawkbit-ddi-starter/src/test/java/org/eclipse/hawkbit/autoconfigure/ddi/security/PreAuthTokenSourceTrustAuthenticationProviderTest.java
+++ /dev/null
@@ -1,144 +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.autoconfigure.ddi.security;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.mockito.Mockito.when;
-
-import java.util.Collections;
-
-import io.qameta.allure.Description;
-import io.qameta.allure.Feature;
-import io.qameta.allure.Story;
-import org.eclipse.hawkbit.security.controller.PreAuthTokenSourceTrustAuthenticationProvider;
-import org.eclipse.hawkbit.security.controller.TenantAwareWebAuthenticationDetails;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.InsufficientAuthenticationException;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
-
-@Feature("Unit Tests - Security")
-@Story("PreAuthToken Source TrustAuthentication Provider Test")
-@ExtendWith(MockitoExtension.class)
-class PreAuthTokenSourceTrustAuthenticationProviderTest {
-
- private static final String REQUEST_SOURCE_IP = "127.0.0.1";
-
- private final PreAuthTokenSourceTrustAuthenticationProvider underTestWithoutSourceIpCheck =
- new PreAuthTokenSourceTrustAuthenticationProvider();
- private final PreAuthTokenSourceTrustAuthenticationProvider underTestWithSourceIpCheck =
- new PreAuthTokenSourceTrustAuthenticationProvider(REQUEST_SOURCE_IP);
-
- @Mock
- private TenantAwareWebAuthenticationDetails webAuthenticationDetailsMock;
-
- @Test
- @Description("Testing in case the containing controllerId in the URI request path does not accord with the controllerId in the request header.")
- void principalAndCredentialsNotTheSameThrowsAuthenticationException() {
- final String principal = "controllerIdURL";
- final String credentials = "controllerIdHeader";
- final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal,
- Collections.singletonList(credentials));
- token.setDetails(webAuthenticationDetailsMock);
-
- assertThatExceptionOfType(BadCredentialsException.class).as("Should not work with wrong credentials")
- .isThrownBy(() -> underTestWithoutSourceIpCheck.authenticate(token));
- }
-
- @Test
- @Description("Testing that the controllerId within the URI request path is the same with the controllerId within the request header and no source IP check is in place.")
- void principalAndCredentialsAreTheSameWithNoSourceIpCheckIsSuccessful() {
- final String principal = "controllerId";
- final String credentials = "controllerId";
- final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal,
- Collections.singletonList(credentials));
- token.setDetails(webAuthenticationDetailsMock);
-
- final Authentication authenticate = underTestWithoutSourceIpCheck.authenticate(token);
- assertThat(authenticate.isAuthenticated()).isTrue();
- }
-
- @Test
- @Description("Testing that the controllerId in the URI request match with the controllerId in the request header but the request are not coming from a trustful source.")
- void principalAndCredentialsAreTheSameButSourceIpRequestNotMatching2() {
- final String remoteAddress = "192.168.1.1";
- final String principal = "controllerId";
- final String credentials = "controllerId";
- final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal,
- Collections.singletonList(credentials));
- token.setDetails(webAuthenticationDetailsMock);
-
- when(webAuthenticationDetailsMock.getRemoteAddress()).thenReturn(remoteAddress);
-
- assertThatExceptionOfType(InsufficientAuthenticationException.class).as("as source is not trusted.")
- .isThrownBy(() -> underTestWithSourceIpCheck.authenticate(token));
- }
-
- @Test
- @Description("Testing that the controllerId in the URI request match with the controllerId in the request header and the source IP is matching the allowed remote IP address.")
- void principalAndCredentialsAreTheSameAndSourceIpIsTrusted() {
- final String principal = "controllerId";
- final String credentials = "controllerId";
- final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal,
- Collections.singletonList(credentials));
- token.setDetails(webAuthenticationDetailsMock);
-
- when(webAuthenticationDetailsMock.getRemoteAddress()).thenReturn(REQUEST_SOURCE_IP);
-
- // test, should throw authentication exception
- final Authentication authenticate = underTestWithSourceIpCheck.authenticate(token);
- assertThat(authenticate.isAuthenticated()).isTrue();
- }
-
- @Test
- @Description("Testing that the controllerId in the URI request match with the controllerId in the request header and the source IP matches one of the allowed remote IP addresses.")
- void principalAndCredentialsAreTheSameAndSourceIpIsWithinList() {
- final String[] trustedIPAddresses = new String[] { "192.168.1.1", "192.168.1.2", REQUEST_SOURCE_IP,
- "192.168.1.3" };
- final String principal = "controllerId";
- final String credentials = "controllerId";
- final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal,
- Collections.singletonList(credentials));
- token.setDetails(webAuthenticationDetailsMock);
-
- when(webAuthenticationDetailsMock.getRemoteAddress()).thenReturn(REQUEST_SOURCE_IP);
-
- final PreAuthTokenSourceTrustAuthenticationProvider underTestWithList = new PreAuthTokenSourceTrustAuthenticationProvider(
- trustedIPAddresses);
-
- // test, should throw authentication exception
- final Authentication authenticate = underTestWithList.authenticate(token);
- assertThat(authenticate.isAuthenticated()).isTrue();
- }
-
- @Test
- @Description("Testing that the controllerId in the URI request match with the controllerId in the request header and the source IP does not match any of the allowed remote IP addresses.")
- void principalAndCredentialsAreTheSameSourceIpListNotMatches() {
- final String[] trustedIPAddresses = new String[] { "192.168.1.1", "192.168.1.2", "192.168.1.3" };
- final String principal = "controllerId";
- final String credentials = "controllerId";
- final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal,
- Collections.singletonList(credentials));
- token.setDetails(webAuthenticationDetailsMock);
-
- when(webAuthenticationDetailsMock.getRemoteAddress()).thenReturn(REQUEST_SOURCE_IP);
-
- final PreAuthTokenSourceTrustAuthenticationProvider underTestWithList = new PreAuthTokenSourceTrustAuthenticationProvider(
- trustedIPAddresses);
-
- assertThatExceptionOfType(InsufficientAuthenticationException.class)
- .isThrownBy(() -> underTestWithList.authenticate(token));
- }
-}
diff --git a/hawkbit-ddi/pom.xml b/hawkbit-ddi/pom.xml
index 592cb465d..d37f67685 100644
--- a/hawkbit-ddi/pom.xml
+++ b/hawkbit-ddi/pom.xml
@@ -25,6 +25,7 @@
hawkbit-ddi-api
hawkbit-ddi-resource
+ hawkbit-ddi-security
hawkbit-ddi-starter
hawkbit-ddi-server
diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/pom.xml b/hawkbit-dmf/hawkbit-dmf-amqp/pom.xml
index d8b50ae59..dd6874237 100644
--- a/hawkbit-dmf/hawkbit-dmf-amqp/pom.xml
+++ b/hawkbit-dmf/hawkbit-dmf-amqp/pom.xml
@@ -34,7 +34,7 @@
org.eclipse.hawkbit
- hawkbit-security-controller
+ hawkbit-security-core
${project.version}
diff --git a/hawkbit-mgmt/hawkbit-mgmt-starter/pom.xml b/hawkbit-mgmt/hawkbit-mgmt-starter/pom.xml
index f89391022..e4702d81f 100644
--- a/hawkbit-mgmt/hawkbit-mgmt-starter/pom.xml
+++ b/hawkbit-mgmt/hawkbit-mgmt-starter/pom.xml
@@ -25,7 +25,7 @@
org.eclipse.hawkbit
- hawkbit-security-controller
+ hawkbit-security-core
${project.version}
diff --git a/hawkbit-security/hawkbit-security-core/pom.xml b/hawkbit-security-core/pom.xml
similarity index 96%
rename from hawkbit-security/hawkbit-security-core/pom.xml
rename to hawkbit-security-core/pom.xml
index 28e965b35..d61d62c5b 100644
--- a/hawkbit-security/hawkbit-security-core/pom.xml
+++ b/hawkbit-security-core/pom.xml
@@ -14,7 +14,7 @@
4.0.0
org.eclipse.hawkbit
- hawkbit-security-parent
+ hawkbit-parent
${revision}
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java
diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java
rename to hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java
diff --git a/hawkbit-security/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java
rename to hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java
diff --git a/hawkbit-security/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java
similarity index 100%
rename from hawkbit-security/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java
rename to hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/AbstractControllerAuthenticationFilter.java b/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/AbstractControllerAuthenticationFilter.java
deleted file mode 100644
index 1d092ce70..000000000
--- a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/AbstractControllerAuthenticationFilter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Copyright (c) 2015 Bosch Software Innovations GmbH and others
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.hawkbit.security.controller;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import lombok.extern.slf4j.Slf4j;
-import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
-import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
-import org.eclipse.hawkbit.security.SystemSecurityContext;
-import org.eclipse.hawkbit.tenancy.TenantAware;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-
-/**
- * An abstraction for all controller based security. Check if the tenant
- * configuration is enabled.
- */
-@Slf4j
-public abstract class AbstractControllerAuthenticationFilter implements PreAuthenticationFilter {
-
- protected final TenantConfigurationManagement tenantConfigurationManagement;
- protected final TenantAware tenantAware;
- protected final SystemSecurityContext systemSecurityContext;
- private final SecurityConfigurationKeyTenantRunner configurationKeyTenantRunner;
-
- protected AbstractControllerAuthenticationFilter(
- final TenantConfigurationManagement systemManagement, final TenantAware tenantAware,
- final SystemSecurityContext systemSecurityContext) {
- this.tenantConfigurationManagement = systemManagement;
- this.tenantAware = tenantAware;
- this.systemSecurityContext = systemSecurityContext;
- this.configurationKeyTenantRunner = new SecurityConfigurationKeyTenantRunner();
- }
-
- @Override
- public boolean isEnable(final ControllerSecurityToken securityToken) {
- return tenantAware.runAsTenant(securityToken.getTenant(), configurationKeyTenantRunner);
- }
-
- @Override
- public Collection getSuccessfulAuthenticationAuthorities() {
- return Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE));
- }
-
- protected abstract String getTenantConfigurationKey();
-
- private final class SecurityConfigurationKeyTenantRunner implements TenantAware.TenantRunner {
-
- @Override
- public Boolean run() {
-
- log.trace("retrieving configuration value for configuration key {}", getTenantConfigurationKey());
- return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
- .getConfigurationValue(getTenantConfigurationKey(), Boolean.class).getValue());
- }
-
- }
-}
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedGatewaySecurityTokenFilter.java b/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedGatewaySecurityTokenFilter.java
deleted file mode 100644
index 9c3c69bea..000000000
--- a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedGatewaySecurityTokenFilter.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Copyright (c) 2015 Bosch Software Innovations GmbH and others
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.hawkbit.security.controller;
-
-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;
-
-/**
- * An pre-authenticated processing filter which extracts (if enabled through
- * configuration) the possibility to authenticate a target based through a
- * gateway security token. This is commonly used for targets connected
- * indirectly via a gateway. This gateway controls multiple targets under the
- * gateway security token which can be set via the {@code TenantsecurityToken}
- * header. {@code Example Header: Authorization: GatewayToken
- * 5d8fSD54fdsFG98DDsa.}
- */
-@Slf4j
-public class ControllerPreAuthenticatedGatewaySecurityTokenFilter extends AbstractControllerAuthenticationFilter {
-
- private static final String GATEWAY_SECURITY_TOKEN_AUTH_SCHEME = "GatewayToken ";
- private static final int OFFSET_GATEWAY_TOKEN = GATEWAY_SECURITY_TOKEN_AUTH_SCHEME.length();
-
- private final GetGatewaySecurityConfigurationKeyTenantRunner gatewaySecurityTokenKeyConfigRunner = new GetGatewaySecurityConfigurationKeyTenantRunner();
-
- /**
- * Constructor.
- *
- * @param tenantConfigurationManagement the tenant management service to retrieve configuration
- * properties
- * @param tenantAware the tenant aware service to get configuration for the specific
- * tenant
- * @param systemSecurityContext the system security context to get access to tenant
- * configuration
- */
- public ControllerPreAuthenticatedGatewaySecurityTokenFilter(
- final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
- final SystemSecurityContext systemSecurityContext) {
- super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
- }
-
- @Override
- public HeaderAuthentication getPreAuthenticatedPrincipal(final ControllerSecurityToken securityToken) {
- final String authHeader = securityToken.getHeader(ControllerSecurityToken.AUTHORIZATION_HEADER);
- if (authHeader != null &&
- authHeader.startsWith(GATEWAY_SECURITY_TOKEN_AUTH_SCHEME) &&
- authHeader.length() > OFFSET_GATEWAY_TOKEN) { // disables empty string token
- log.debug("found authorization header with scheme {} using target security token for authentication",
- GATEWAY_SECURITY_TOKEN_AUTH_SCHEME);
- return new HeaderAuthentication(securityToken.getControllerId(),
- authHeader.substring(OFFSET_GATEWAY_TOKEN));
- }
- log.debug(
- "security token filter is enabled but request does not contain either the necessary security token {} or the authorization header with scheme {}",
- securityToken, GATEWAY_SECURITY_TOKEN_AUTH_SCHEME);
- return null;
- }
-
- @Override
- public HeaderAuthentication getPreAuthenticatedCredentials(final ControllerSecurityToken securityToken) {
- final String gatewayToken = tenantAware.runAsTenant(securityToken.getTenant(),
- gatewaySecurityTokenKeyConfigRunner);
- return new HeaderAuthentication(securityToken.getControllerId(), gatewayToken);
- }
-
- @Override
- protected String getTenantConfigurationKey() {
- return TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED;
- }
-
- private final class GetGatewaySecurityConfigurationKeyTenantRunner implements TenantAware.TenantRunner {
-
- @Override
- public String run() {
- log.trace("retrieving configuration value for configuration key {}",
- TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY);
-
- return systemSecurityContext
- .runAsSystem(() -> tenantConfigurationManagement
- .getConfigurationValue(
- TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class)
- .getValue());
- }
- }
-
-}
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityHeaderFilter.java b/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityHeaderFilter.java
deleted file mode 100644
index 7df8c9813..000000000
--- a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityHeaderFilter.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * Copyright (c) 2015 Bosch Software Innovations GmbH and others
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.hawkbit.security.controller;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A pre-authenticated processing filter which extracts the principal from a
- * request URI and the credential from a request header in a the
- * {@link ControllerSecurityToken}.
- */
-@Slf4j
-public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractControllerAuthenticationFilter {
-
- private static final Logger LOG_SECURITY_AUTH = LoggerFactory.getLogger("server-security.authentication");
-
- private final GetSecurityAuthorityNameTenantRunner sslIssuerNameConfigTenantRunner = new GetSecurityAuthorityNameTenantRunner();
- // Example Headers with Cert Information
- // Clientip: 217.24.201.180
- // X-Forwarded-Proto: https
- // X-Ssl-Client-Cn: my.name
- // X-Ssl-Client-Dn:
- // CN=my.name,CN=O,CN=R,CN=DE,CN=BOSCH,CN=pki,DC=bosch,DC=com
- // X-Ssl-Client-Hash: 7f:87:cb:b5:9c:e0:c5:0a:1a:a6:57:69:0f:ca:0a:95
- // X-Ssl-Client-Notafter: Dec 18 08:02:45 2017 GMT
- // X-Ssl-Client-Notbefore: Dec 18 07:32:45 2014 GMT
- // X-Ssl-Client-Verify: ok
- // X-Ssl-Issuer: CN=Bosch-CA1-DE,CN=PKI,DC=Bosch,DC=com
- // X-Ssl-Issuer-Dn-1: CN=Bosch-CA-DE,CN=PKI,DC=Bosch,DC=com
- // X-Ssl-Issuer-Hash-1: ae:11:f5:6a:0a:e8:74:50:81:0e:0c:37:ec:c5:22:fc
- private final String caCommonNameHeader;
- // the X-Ssl-Issuer-Hash basic header: Contains the x509 fingerprint hash, this
- // header exists multiple times in the request for all trusted chains.
- private final String sslIssuerHashBasicHeader;
-
- /**
- * Constructor.
- *
- * @param caCommonNameHeader the http-header which holds the common-name of the certificate
- * @param caAuthorityNameHeader the http-header which holds the ca-authority name of the
- * certificate
- * @param tenantConfigurationManagement the tenant management service to retrieve configuration
- * properties
- * @param tenantAware the tenant aware service to get configuration for the specific
- * tenant
- * @param systemSecurityContext the system security context to get access to tenant
- * configuration
- */
- public ControllerPreAuthenticatedSecurityHeaderFilter(final String caCommonNameHeader,
- final String caAuthorityNameHeader, final TenantConfigurationManagement tenantConfigurationManagement,
- final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
- super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
- this.caCommonNameHeader = caCommonNameHeader;
- this.sslIssuerHashBasicHeader = caAuthorityNameHeader;
- }
-
- @Override
- public HeaderAuthentication getPreAuthenticatedPrincipal(final ControllerSecurityToken securityToken) {
- // retrieve the common name header and the authority name header from
- // the http request and combine them together
- final String commonNameValue = securityToken.getHeader(caCommonNameHeader);
- final String knownSslIssuerConfigurationValue = tenantAware.runAsTenant(securityToken.getTenant(),
- sslIssuerNameConfigTenantRunner);
- final String sslIssuerHashValue = getIssuerHashHeader(securityToken, knownSslIssuerConfigurationValue);
- if (commonNameValue != null && log.isTraceEnabled()) {
- log.trace("Found commonNameHeader {}={}, using as credentials", caCommonNameHeader, commonNameValue);
- }
- if (sslIssuerHashValue != null && log.isTraceEnabled()) {
- log.trace("Found sslIssuerHash ****, using as credentials for tenant {}", securityToken.getTenant());
- }
-
- if (commonNameValue != null && sslIssuerHashValue != null) {
- return new HeaderAuthentication(commonNameValue, sslIssuerHashValue);
- }
- return null;
- }
-
- @Override
- public Object getPreAuthenticatedCredentials(final ControllerSecurityToken securityToken) {
- final String authorityNameConfigurationValue = tenantAware.runAsTenant(securityToken.getTenant(),
- sslIssuerNameConfigTenantRunner);
-
- // in case of legacy download artifact, the controller ID is not in the
- // URL path, so then we just use the common name header
- final String controllerId = //
- (securityToken.getControllerId() == null || "anonymous".equals(securityToken.getControllerId()) //
- ? securityToken.getHeader(caCommonNameHeader)
- : securityToken.getControllerId());
-
- final List knownHashes = splitMultiHashBySemicolon(authorityNameConfigurationValue);
- return knownHashes.stream().map(hashItem -> new HeaderAuthentication(controllerId, hashItem)).collect(Collectors.toSet());
- }
-
- @Override
- protected String getTenantConfigurationKey() {
- return TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
- }
-
- private static List splitMultiHashBySemicolon(final String knownIssuerHashes) {
- return Arrays.stream(knownIssuerHashes.split("[;,]")).map(String::toLowerCase).toList();
- }
-
- /**
- * Iterates over the {@link #sslIssuerHashBasicHeader} basic header
- * {@code X-Ssl-Issuer-Hash-%d} and try to find the same hash as known. It's ok
- * if we find the hash in any the trusted CA chain to accept this request for
- * this tenant.
- */
- @SuppressWarnings("java:S2629") // check if debug is enabled is maybe heavier then evaluation
- private String getIssuerHashHeader(final ControllerSecurityToken securityToken, final String knownIssuerHashes) {
- // there may be several knownIssuerHashes configured for the tenant
- final List knownHashes = splitMultiHashBySemicolon(knownIssuerHashes);
-
- // iterate over the headers until we get a null header.
- int iHeader = 1;
- String foundHash;
- while ((foundHash = securityToken.getHeader(String.format(sslIssuerHashBasicHeader, iHeader))) != null) {
- if (knownHashes.contains(foundHash.toLowerCase())) {
- if (log.isTraceEnabled()) {
- log.trace("Found matching ssl issuer hash at position {}", iHeader);
- }
- return foundHash.toLowerCase();
- }
- iHeader++;
- }
- LOG_SECURITY_AUTH.debug(
- "Certificate request but no matching hash found in headers {} for common name {} in request",
- sslIssuerHashBasicHeader, securityToken.getHeader(caCommonNameHeader));
- return null;
- }
-
- private final class GetSecurityAuthorityNameTenantRunner implements TenantAware.TenantRunner {
-
- @Override
- public String run() {
- return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(
- TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class).getValue());
- }
- }
-}
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityTokenFilter.java b/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityTokenFilter.java
deleted file mode 100644
index aa30529d9..000000000
--- a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/ControllerPreAuthenticatedSecurityTokenFilter.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * Copyright (c) 2015 Bosch Software Innovations GmbH and others
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.hawkbit.security.controller;
-
-import java.util.Optional;
-
-import lombok.extern.slf4j.Slf4j;
-import org.eclipse.hawkbit.repository.ControllerManagement;
-import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
-import org.eclipse.hawkbit.repository.model.Target;
-import org.eclipse.hawkbit.security.SystemSecurityContext;
-import org.eclipse.hawkbit.tenancy.TenantAware;
-import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
-
-/**
- * An pre-authenticated processing filter which extracts (if enabled through
- * configuration) the possibility to authenticate a target based on its target
- * security-token with the {@code Authorization} HTTP header.
- * {@code Example Header: Authorization: TargetToken
- * 5d8fSD54fdsFG98DDsa.}
- */
-@Slf4j
-public class ControllerPreAuthenticatedSecurityTokenFilter extends AbstractControllerAuthenticationFilter {
-
- private static final String TARGET_SECURITY_TOKEN_AUTH_SCHEME = "TargetToken ";
- private static final int OFFSET_TARGET_TOKEN = TARGET_SECURITY_TOKEN_AUTH_SCHEME.length();
-
- private final ControllerManagement controllerManagement;
-
- /**
- * Constructor.
- *
- * @param tenantConfigurationManagement the tenant management service to retrieve configuration
- * properties
- * @param controllerManagement the controller management to retrieve the specific target
- * security token to verify
- * @param tenantAware the tenant aware service to get configuration for the specific
- * tenant
- * @param systemSecurityContext the system security context to get access to tenant
- * configuration
- */
- public ControllerPreAuthenticatedSecurityTokenFilter(
- final TenantConfigurationManagement tenantConfigurationManagement,
- final ControllerManagement controllerManagement, final TenantAware tenantAware,
- final SystemSecurityContext systemSecurityContext) {
- super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
- this.controllerManagement = controllerManagement;
- }
-
- @Override
- public HeaderAuthentication getPreAuthenticatedPrincipal(final ControllerSecurityToken securityToken) {
- final String controllerId = resolveControllerId(securityToken);
- final String authHeader = securityToken.getHeader(ControllerSecurityToken.AUTHORIZATION_HEADER);
- if ((authHeader != null) && authHeader.startsWith(TARGET_SECURITY_TOKEN_AUTH_SCHEME)) {
- log.debug("found authorization header with scheme {} using target security token for authentication",
- TARGET_SECURITY_TOKEN_AUTH_SCHEME);
- return new HeaderAuthentication(controllerId, authHeader.substring(OFFSET_TARGET_TOKEN));
- }
- log.debug(
- "security token filter is enabled but requst does not contain either the necessary path variables {} or the authorization header with scheme {}",
- securityToken, TARGET_SECURITY_TOKEN_AUTH_SCHEME);
- return null;
- }
-
- @Override
- public HeaderAuthentication getPreAuthenticatedCredentials(final ControllerSecurityToken securityToken) {
- final Optional target = systemSecurityContext.runAsSystemAsTenant(() -> {
- if (securityToken.getTargetId() != null) {
- return controllerManagement.get(securityToken.getTargetId());
- }
- return controllerManagement.getByControllerId(securityToken.getControllerId());
- }, securityToken.getTenant());
-
- return target.map(t -> new HeaderAuthentication(
- t.getControllerId(), systemSecurityContext.runAsSystemAsTenant(t::getSecurityToken, securityToken.getTenant())))
- .orElse(null);
- }
-
- @Override
- protected String getTenantConfigurationKey() {
- return TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED;
- }
-
- private String resolveControllerId(final ControllerSecurityToken securityToken) {
- if (securityToken.getControllerId() != null) {
- return securityToken.getControllerId();
- }
- final Optional foundTarget = systemSecurityContext.runAsSystemAsTenant(
- () -> controllerManagement.get(securityToken.getTargetId()), securityToken.getTenant());
- return foundTarget.map(Target::getControllerId).orElse(null);
- }
-}
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/HeaderAuthentication.java b/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/HeaderAuthentication.java
deleted file mode 100644
index 91ccf5fb0..000000000
--- a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/HeaderAuthentication.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Copyright (c) 2015 Bosch Software Innovations GmbH and others
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.hawkbit.security.controller;
-
-/**
- * The authentication principal and credentials object which holds the
- * controller-id and the authority name from the http-headers as principal or
- * from the http-url and tenant configuration for the credentials.
- */
-final class HeaderAuthentication {
-
- private final String controllerId;
- private final String headerAuth;
-
- HeaderAuthentication(final String controllerId, final String headerAuth) {
- this.controllerId = controllerId;
- this.headerAuth = headerAuth;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((controllerId == null) ? 0 : controllerId.hashCode());
- result = prime * result + ((headerAuth == null) ? 0 : headerAuth.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final HeaderAuthentication other = (HeaderAuthentication) obj;
- if (controllerId == null) {
- if (other.controllerId != null) {
- return false;
- }
- } else if (!controllerId.equals(other.controllerId)) {
- return false;
- }
- if (headerAuth == null) {
- if (other.headerAuth != null) {
- return false;
- }
- } else if (!headerAuth.equals(other.headerAuth)) {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- // only the controller ID because the principal is stored as string for
- // audit information
- // etc.
- return controllerId;
- }
-
-}
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/PreAuthTokenSourceTrustAuthenticationProvider.java b/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/PreAuthTokenSourceTrustAuthenticationProvider.java
deleted file mode 100644
index d71ad6c82..000000000
--- a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/PreAuthTokenSourceTrustAuthenticationProvider.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/**
- * Copyright (c) 2015 Bosch Software Innovations GmbH and others
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.hawkbit.security.controller;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.InsufficientAuthenticationException;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
-
-/**
- * An spring authentication provider which supports authentication tokens of
- * type {@link PreAuthenticatedAuthenticationToken} created by the
- * {@link ControllerPreAuthenticatedSecurityHeaderFilter}.
- *
- * Additionally to the authentication token providing the principal and the
- * credentials which must be match, this authentication provider can also check
- * the remote IP address of the request.
- *
- * E.g. The request path is /controller/v1/{controllerId} then the controllerId
- * in the path is the principal. The credentials are the extracted information
- * from e.g. a certificate provided by an reverse proxy. Due this request is
- * only allowed from a specific source address this authentication manager can
- * also check the remote IP address of the request.
- */
-@Slf4j
-public class PreAuthTokenSourceTrustAuthenticationProvider implements AuthenticationProvider {
-
- private final List authorizedSourceIps;
-
- /**
- * Creates a new PreAuthTokenSourceTrustAuthenticationProvider without
- * source IPs, which disables the source IP check.
- */
- public PreAuthTokenSourceTrustAuthenticationProvider() {
- authorizedSourceIps = null;
- }
-
- /**
- * Creates a new PreAuthTokenSourceTrustAuthenticationProvider with given
- * source IP addresses which are trusted and should be checked against the
- * request remote IP address.
- *
- * @param authorizedSourceIps a list of IP addresses.
- */
- public PreAuthTokenSourceTrustAuthenticationProvider(final List authorizedSourceIps) {
- this.authorizedSourceIps = authorizedSourceIps;
- }
-
- /**
- * Creates a new PreAuthTokenSourceTrustAuthenticationProvider with given
- * source IP addresses which are trusted and should be checked against the
- * request remote IP address.
- *
- * @param authorizedSourceIps a list of IP addresses.
- */
- public PreAuthTokenSourceTrustAuthenticationProvider(final String... authorizedSourceIps) {
- this.authorizedSourceIps = new ArrayList<>();
- this.authorizedSourceIps.addAll(Arrays.asList(authorizedSourceIps));
- }
-
- @Override
- public Authentication authenticate(final Authentication authentication) {
- if (!supports(authentication.getClass())) {
- return null;
- }
-
- final PreAuthenticatedAuthenticationToken token = (PreAuthenticatedAuthenticationToken) authentication;
- final Object credentials = token.getCredentials();
- final Object principal = token.getPrincipal();
- final Object tokenDetails = token.getDetails();
- final Collection authorities = token.getAuthorities();
-
- if (principal == null) {
- throw new BadCredentialsException("The provided principal and credentials are not match");
- }
-
- final boolean successAuthentication = calculateAuthenticationSuccess(principal, credentials, tokenDetails);
-
- if (successAuthentication) {
- final PreAuthenticatedAuthenticationToken successToken = new PreAuthenticatedAuthenticationToken(principal,
- credentials, authorities);
- successToken.setDetails(tokenDetails);
- return successToken;
- }
-
- throw new BadCredentialsException("The provided principal and credentials are not match");
- }
-
- @Override
- public boolean supports(final Class> authentication) {
- return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
- }
-
- /**
- * The credentials may either be of type HeaderAuthentication or of type
- * Collection depending on the authentication mode in
- * use (the latter is used in case of trusted reverse-proxy). It is checked
- * whether principal equals credentials (respectively if credentials
- * contains principal in case of collection) because we want to check if
- * e.g. controllerId containing in the URL equals the controllerId in the
- * special header set by the reverse-proxy which extracted the CN from the
- * certificate.
- *
- * @param principal the {@link HeaderAuthentication} from the header
- * @param credentials a single {@link HeaderAuthentication} or a Collection of
- * HeaderAuthentication
- * @param tokenDetails authentication details
- * @return true if authentication succeeded, otherwise
- * false
- */
- private boolean calculateAuthenticationSuccess(final Object principal, final Object credentials,
- final Object tokenDetails) {
- boolean successAuthentication = false;
- if (credentials instanceof Collection) {
- final Collection> multiValueCredentials = (Collection>) credentials;
- if (multiValueCredentials.contains(principal)) {
- successAuthentication = checkSourceIPAddressIfNeccessary(tokenDetails);
- }
- } else if (principal.equals(credentials)) {
- successAuthentication = checkSourceIPAddressIfNeccessary(tokenDetails);
- }
-
- return successAuthentication;
- }
-
- private boolean checkSourceIPAddressIfNeccessary(final Object tokenDetails) {
- boolean success = authorizedSourceIps == null;
- String remoteAddress = null;
- // controllerIds in URL path and request header are the same but is the
- // request coming
- // from a trustful source, like the reverse proxy.
- if (authorizedSourceIps != null) {
- if (tokenDetails instanceof TenantAwareWebAuthenticationDetails tenantAwareWebAuthenticationDetails) {
- remoteAddress = tenantAwareWebAuthenticationDetails.getRemoteAddress();
- if (authorizedSourceIps.contains(remoteAddress)) {
- // source ip matches the given pattern -> authenticated
- success = true;
- }
- } else {
- // is not of type WebAuthenticationDetails, then we cannot
- // determine the remote address!
- log.error(
- "Cannot determine the controller remote-ip-address based on the given authentication token - {} , token details are not TenantAwareWebAuthenticationDetails! ",
- tokenDetails);
- success = false;
- }
- }
-
- if (!success) {
- throw new InsufficientAuthenticationException("The remote source IP address " + remoteAddress
- + " is not in the list of trusted IP addresses " + authorizedSourceIps);
- }
-
- // no trusted IP check, because no authorizedSourceIPs configuration
- return true;
- }
-
-}
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/PreAuthenticationFilter.java b/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/PreAuthenticationFilter.java
deleted file mode 100644
index 152af7026..000000000
--- a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/PreAuthenticationFilter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Copyright (c) 2015 Bosch Software Innovations GmbH and others
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.hawkbit.security.controller;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-
-/**
- * Interface for Pre Authentication.
- */
-public interface PreAuthenticationFilter {
-
- /**
- * Check if the filter is enabled.
- *
- * @param securityToken the secruity info
- * @return true is enabled false diabled
- */
- boolean isEnable(ControllerSecurityToken securityToken);
-
- /**
- * Extract the principal information from the current securityToken.
- *
- * @param securityToken the securityToken
- * @return the extracted tenant and controller id
- */
- HeaderAuthentication getPreAuthenticatedPrincipal(ControllerSecurityToken securityToken);
-
- /**
- * Extract the principal credentials from the current securityToken.
- *
- * @param securityToken the securityToken
- * @return the extracted tenant and controller id
- */
- Object getPreAuthenticatedCredentials(ControllerSecurityToken securityToken);
-
- /**
- * Allows to add additional authorities to the successful authenticated token.
- *
- * @return the authorities granted to the principal, or an empty collection if
- * the token has not been authenticated. Never null.
- * @see Authentication#getAuthorities()
- */
- default Collection getSuccessfulAuthenticationAuthorities() {
- return Collections.emptyList();
- }
-
-}
diff --git a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/TenantAwareWebAuthenticationDetails.java b/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/TenantAwareWebAuthenticationDetails.java
deleted file mode 100644
index 0687d2b27..000000000
--- a/hawkbit-security/hawkbit-security-controller/src/main/java/org/eclipse/hawkbit/security/controller/TenantAwareWebAuthenticationDetails.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Copyright (c) 2015 Bosch Software Innovations GmbH and others
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.hawkbit.security.controller;
-
-import java.io.Serial;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
-
-/**
- * Extends the {@link TenantAwareAuthenticationDetails} to web information to
- * retrieve also e.g. the remoteAddress of the {@link HttpServletRequest} when
- * authenticating the requested controller e.g. based on the security header and
- * trusted IP address we need the remote address of the http request to verify
- * the e.g. the reverse proxy is trusted and allowed to set the header.
- */
-public class TenantAwareWebAuthenticationDetails extends TenantAwareAuthenticationDetails {
-
- @Serial
- private static final long serialVersionUID = 1L;
-
- private final String remoteAddress;
-
- /**
- * @param tenant the current tenant
- * @param remoteAddress the remote address of this web request
- * @param controller {@code true} indicates this is an controller HTTP request
- * otherwise {@code false}.
- */
- public TenantAwareWebAuthenticationDetails(final String tenant, final String remoteAddress,
- final boolean controller) {
- super(tenant, controller);
- this.remoteAddress = remoteAddress;
- }
-
- /**
- * @return the remoteAddress
- */
- public String getRemoteAddress() {
- return remoteAddress;
- }
-}
diff --git a/hawkbit-security/pom.xml b/hawkbit-security/pom.xml
deleted file mode 100644
index aff058c70..000000000
--- a/hawkbit-security/pom.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
- 4.0.0
-
- org.eclipse.hawkbit
- hawkbit-parent
- ${revision}
-
-
- hawkbit-security-parent
- hawkBit :: Security :: Parent
- pom
-
-
- hawkbit-security-core
- hawkbit-security-controller
-
-
\ No newline at end of file
diff --git a/hawkbit-test-report/pom.xml b/hawkbit-test-report/pom.xml
index 3eeb7a19e..65acd4810 100644
--- a/hawkbit-test-report/pom.xml
+++ b/hawkbit-test-report/pom.xml
@@ -34,7 +34,7 @@
org.eclipse.hawkbit
- hawkbit-security-controller
+ hawkbit-ddi-security
${project.version}
diff --git a/pom.xml b/pom.xml
index 3b6fcbff5..7fb15ffbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -132,10 +132,10 @@
hawkbit-core
- hawkbit-rest-core
- hawkbit-security
+ hawkbit-security-core
hawkbit-artifact
hawkbit-repository
+ hawkbit-rest-core
hawkbit-autoconfigure
hawkbit-mgmt
@@ -144,7 +144,6 @@
hawkbit-monolith
hawkbit-simple-ui
-
hawkbit-sdk
hawkbit-test-report