Code format hawkbit-security-integration (#1934)

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-11-05 11:19:11 +02:00
committed by GitHub
parent 2c2ed8f8ab
commit 51ac49db64
13 changed files with 145 additions and 179 deletions

View File

@@ -9,50 +9,50 @@
SPDX-License-Identifier: EPL-2.0
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-parent</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hawkbit-security-integration</artifactId>
<name>hawkBit :: Security Integration</name>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-parent</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hawkbit-security-integration</artifactId>
<name>hawkBit :: Security Integration</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-jpa</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- TEST -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-jpa</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -28,8 +28,8 @@ public abstract class AbstractControllerAuthenticationFilter implements PreAuthe
protected final TenantConfigurationManagement tenantConfigurationManagement;
protected final TenantAware tenantAware;
private final SecurityConfigurationKeyTenantRunner configurationKeyTenantRunner;
protected final SystemSecurityContext systemSecurityContext;
private final SecurityConfigurationKeyTenantRunner configurationKeyTenantRunner;
protected AbstractControllerAuthenticationFilter(final TenantConfigurationManagement systemManagement,
final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
@@ -39,14 +39,20 @@ public abstract class AbstractControllerAuthenticationFilter implements PreAuthe
this.configurationKeyTenantRunner = new SecurityConfigurationKeyTenantRunner();
}
protected abstract String getTenantConfigurationKey();
@Override
public boolean isEnable(final DmfTenantSecurityToken securityToken) {
return tenantAware.runAsTenant(securityToken.getTenant(), configurationKeyTenantRunner);
}
@Override
public Collection<GrantedAuthority> getSuccessfulAuthenticationAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE));
}
protected abstract String getTenantConfigurationKey();
private final class SecurityConfigurationKeyTenantRunner implements TenantAware.TenantRunner<Boolean> {
@Override
public Boolean run() {
@@ -56,9 +62,4 @@ public abstract class AbstractControllerAuthenticationFilter implements PreAuthe
}
}
@Override
public Collection<GrantedAuthority> getSuccessfulAuthenticationAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE));
}
}

View File

@@ -27,7 +27,7 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.T
*/
@Slf4j
public class ControllerPreAuthenticateSecurityTokenFilter 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();
@@ -35,19 +35,15 @@ public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractContro
/**
* 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
*
* @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 ControllerPreAuthenticateSecurityTokenFilter(
final TenantConfigurationManagement tenantConfigurationManagement,
@@ -82,10 +78,15 @@ public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractContro
}, securityToken.getTenant());
return target.map(t -> new HeaderAuthentication(t.getControllerId(),
systemSecurityContext.runAsSystemAsTenant(() -> t.getSecurityToken(), securityToken.getTenant())))
systemSecurityContext.runAsSystemAsTenant(() -> t.getSecurityToken(), securityToken.getTenant())))
.orElse(null);
}
@Override
protected String getTenantConfigurationKey() {
return TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED;
}
private String resolveControllerId(final DmfTenantSecurityToken securityToken) {
if (securityToken.getControllerId() != null) {
return securityToken.getControllerId();
@@ -94,9 +95,4 @@ public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractContro
() -> controllerManagement.get(securityToken.getTargetId()), securityToken.getTenant());
return foundTarget.map(Target::getControllerId).orElse(null);
}
@Override
protected String getTenantConfigurationKey() {
return TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED;
}
}

View File

@@ -24,16 +24,13 @@ public class ControllerPreAuthenticatedAnonymousDownload extends AbstractControl
/**
* 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
*
* @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 ControllerPreAuthenticatedAnonymousDownload(
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,

View File

@@ -12,7 +12,7 @@ package org.eclipse.hawkbit.security;
/**
* An anonymous controller filter which is only enabled in case of anonymous
* access is granted. This should only be for development purposes.
*
*
* @see DdiSecurityProperties
*/
public class ControllerPreAuthenticatedAnonymousFilter implements PreAuthenticationFilter {
@@ -20,14 +20,18 @@ public class ControllerPreAuthenticatedAnonymousFilter implements PreAuthenticat
private final DdiSecurityProperties ddiSecurityConfiguration;
/**
* @param ddiSecurityConfiguration
* the security configuration which holds the configuration if
* anonymous is enabled or not
* @param ddiSecurityConfiguration the security configuration which holds the configuration if
* anonymous is enabled or not
*/
public ControllerPreAuthenticatedAnonymousFilter(final DdiSecurityProperties ddiSecurityConfiguration) {
this.ddiSecurityConfiguration = ddiSecurityConfiguration;
}
@Override
public boolean isEnable(final DmfTenantSecurityToken securityToken) {
return ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled();
}
@Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final DmfTenantSecurityToken securityToken) {
return new HeaderAuthentication(securityToken.getControllerId(), securityToken.getControllerId());
@@ -37,9 +41,4 @@ public class ControllerPreAuthenticatedAnonymousFilter implements PreAuthenticat
public HeaderAuthentication getPreAuthenticatedCredentials(final DmfTenantSecurityToken securityToken) {
return new HeaderAuthentication(securityToken.getControllerId(), securityToken.getControllerId());
}
@Override
public boolean isEnable(final DmfTenantSecurityToken securityToken) {
return ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled();
}
}

View File

@@ -25,7 +25,7 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.T
*/
@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();
@@ -33,16 +33,13 @@ public class ControllerPreAuthenticatedGatewaySecurityTokenFilter extends Abstra
/**
* 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
*
* @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,

View File

@@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory;
*/
@Slf4j
public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractControllerAuthenticationFilter {
private static final Logger LOG_SECURITY_AUTH = LoggerFactory.getLogger("server-security.authentication");
private final GetSecurityAuthorityNameTenantRunner sslIssuerNameConfigTenantRunner = new GetSecurityAuthorityNameTenantRunner();
@@ -52,20 +52,15 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont
/**
* 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
* @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,
@@ -113,6 +108,15 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont
.collect(Collectors.toSet());
}
@Override
protected String getTenantConfigurationKey() {
return TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
}
private static List<String> splitMultiHashBySemicolon(final String knownIssuerHashes) {
return Arrays.stream(knownIssuerHashes.split("[;,]")).map(String::toLowerCase).collect(Collectors.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
@@ -142,20 +146,12 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont
return null;
}
@Override
protected String getTenantConfigurationKey() {
return TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
}
private final class GetSecurityAuthorityNameTenantRunner implements TenantAware.TenantRunner<String> {
@Override
public String run() {
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class).getValue());
}
}
private static List<String> splitMultiHashBySemicolon(final String knownIssuerHashes) {
return Arrays.stream(knownIssuerHashes.split("[;,]")).map(String::toLowerCase).collect(Collectors.toList());
}
}

View File

@@ -28,22 +28,20 @@ import lombok.Data;
public class DmfTenantSecurityToken {
public static final String AUTHORIZATION_HEADER = "Authorization";
@JsonProperty
private String tenant;
@JsonProperty
private final Long tenantId;
@JsonProperty
private final String controllerId;
@JsonProperty
private final Long targetId;
@JsonProperty
private String tenant;
@JsonProperty
private Map<String, String> headers;
/**
* Constructor.
*
*
* @param tenant the tenant for the security token
* @param tenantId alternative tenant identification by technical ID
* @param controllerId the ID of the controller for the security token
@@ -61,7 +59,7 @@ public class DmfTenantSecurityToken {
/**
* Constructor.
*
*
* @param tenant the tenant for the security token
* @param controllerId the ID of the controller for the security token
*/
@@ -71,7 +69,7 @@ public class DmfTenantSecurityToken {
/**
* Constructor.
*
*
* @param tenantId the tenant for the security token
* @param targetId target identification by technical ID
*/
@@ -81,9 +79,8 @@ public class DmfTenantSecurityToken {
/**
* Gets a header value.
*
* @param name
* of header
*
* @param name of header
* @return the value
*/
public String getHeader(final String name) {
@@ -96,10 +93,9 @@ public class DmfTenantSecurityToken {
/**
* Associates the specified header value with the specified name.
*
*
* @param name of the header
* @param value of the header
*
* @return the previous value associated with the <tt>name</tt>, or <tt>null</tt> if there was no mapping for <tt>name</tt>.
*/
public String putHeader(final String name, final String value) {

View File

@@ -13,11 +13,9 @@ package org.eclipse.hawkbit.security;
* 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;

View File

@@ -38,7 +38,7 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
*/
@Slf4j
public class PreAuthTokenSourceTrustAuthenticationProvider implements AuthenticationProvider {
private final List<String> authorizedSourceIps;
/**
@@ -54,8 +54,7 @@ public class PreAuthTokenSourceTrustAuthenticationProvider implements Authentica
* source IP addresses which are trusted and should be checked against the
* request remote IP address.
*
* @param authorizedSourceIps
* a list of IP addresses.
* @param authorizedSourceIps a list of IP addresses.
*/
public PreAuthTokenSourceTrustAuthenticationProvider(final List<String> authorizedSourceIps) {
this.authorizedSourceIps = authorizedSourceIps;
@@ -66,8 +65,7 @@ public class PreAuthTokenSourceTrustAuthenticationProvider implements Authentica
* source IP addresses which are trusted and should be checked against the
* request remote IP address.
*
* @param authorizedSourceIps
* a list of IP addresses.
* @param authorizedSourceIps a list of IP addresses.
*/
public PreAuthTokenSourceTrustAuthenticationProvider(final String... authorizedSourceIps) {
this.authorizedSourceIps = new ArrayList<>();
@@ -104,8 +102,12 @@ public class PreAuthTokenSourceTrustAuthenticationProvider implements Authentica
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<HeaderAuthentication> depending on the authentication mode in
* use (the latter is used in case of trusted reverse-proxy). It is checked
@@ -115,13 +117,10 @@ public class PreAuthTokenSourceTrustAuthenticationProvider implements Authentica
* 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
* @param principal the {@link HeaderAuthentication} from the header
* @param credentials a single {@link HeaderAuthentication} or a Collection of
* HeaderAuthentication
* @param tokenDetails authentication details
* @return <code>true</code> if authentication succeeded, otherwise
* <code>false</code>
*/
@@ -172,9 +171,4 @@ public class PreAuthTokenSourceTrustAuthenticationProvider implements Authentica
return true;
}
@Override
public boolean supports(final Class<?> authentication) {
return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
}
}

View File

@@ -19,9 +19,6 @@ import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
* 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 {
@@ -29,13 +26,10 @@ public class TenantAwareWebAuthenticationDetails extends TenantAwareAuthenticati
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}.
* @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) {

View File

@@ -11,6 +11,8 @@ package org.eclipse.hawkbit.security;
import static org.assertj.core.api.Assertions.assertThat;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.TenantAware;
@@ -21,9 +23,6 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
*
*/

View File

@@ -14,6 +14,9 @@ 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;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
@@ -24,10 +27,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Unit Tests - Security")
@Story("Issuer hash based authentication")
@ExtendWith(MockitoExtension.class)
@@ -74,7 +73,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilterTest {
// use single known hash
when(tenantConfigurationManagementMock.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_SINGLE_HASH);
.thenReturn(CONFIG_VALUE_SINGLE_HASH);
assertThat(underTest.getPreAuthenticatedPrincipal(securityToken)).isNotNull();
}
@@ -84,7 +83,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilterTest {
// use multiple known hashes
when(tenantConfigurationManagementMock.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_MULTI_HASH);
.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();
@@ -97,7 +96,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilterTest {
// use single known hash
when(tenantConfigurationManagementMock.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_MULTI_HASH);
.thenReturn(CONFIG_VALUE_MULTI_HASH);
assertThat(underTest.getPreAuthenticatedPrincipal(securityToken)).isNull();
}
@@ -112,7 +111,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilterTest {
when(tenantConfigurationManagementMock.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_MULTI_HASH);
.thenReturn(CONFIG_VALUE_MULTI_HASH);
final Collection<HeaderAuthentication> credentials1 = (Collection<HeaderAuthentication>) underTest
.getPreAuthenticatedCredentials(securityToken1);