Code format hawkbit-http-security (#1935)

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-11-05 11:20:37 +02:00
committed by GitHub
parent 51ac49db64
commit ea56402aaa
8 changed files with 135 additions and 158 deletions

View File

@@ -9,54 +9,55 @@
SPDX-License-Identifier: EPL-2.0 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"> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
<modelVersion>4.0.0</modelVersion> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <modelVersion>4.0.0</modelVersion>
<artifactId>hawkbit-parent</artifactId> <parent>
<version>${revision}</version> <artifactId>hawkbit-parent</artifactId>
<groupId>org.eclipse.hawkbit</groupId> <version>${revision}</version>
</parent> <groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-http-security</artifactId> </parent>
<name>hawkBit :: HTTP Security</name> <artifactId>hawkbit-http-security</artifactId>
<name>hawkBit :: HTTP Security</name>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-api</artifactId> <artifactId>hawkbit-repository-api</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-security-core</artifactId> <artifactId>hawkbit-security-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-security-integration</artifactId> <artifactId>hawkbit-security-integration</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId> <artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.ben-manes.caffeine</groupId> <groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId> <artifactId>caffeine</artifactId>
</dependency> </dependency>
<!-- Test --> <!-- Test -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.qameta.allure</groupId> <groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId> <artifactId>allure-junit5</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -39,10 +39,12 @@ import org.springframework.util.AntPathMatcher;
* based on this information. * based on this information.
*/ */
public abstract class AbstractHttpControllerAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter { 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 TENANT_PLACE_HOLDER = "tenant";
private static final String CONTROLLER_ID_PLACE_HOLDER = "controllerId"; private static final String CONTROLLER_ID_PLACE_HOLDER = "controllerId";
/** /**
* requestURIPathPattern the request URI path pattern in ANT style * requestURIPathPattern the request URI path pattern in ANT style
* containing the placeholder key for retrieving the principal from the URI * containing the placeholder key for retrieving the principal from the URI
@@ -50,20 +52,15 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
*/ */
private static final String CONTROLLER_REQUEST_ANT_PATTERN = "/{" + TENANT_PLACE_HOLDER + "}/controller/v1" + "/{" private static final String CONTROLLER_REQUEST_ANT_PATTERN = "/{" + TENANT_PLACE_HOLDER + "}/controller/v1" + "/{"
+ CONTROLLER_ID_PLACE_HOLDER + "}/**"; + CONTROLLER_ID_PLACE_HOLDER + "}/**";
private static final String CONTROLLER_DL_REQUEST_ANT_PATTERN = "/{" + TENANT_PLACE_HOLDER private static final String CONTROLLER_DL_REQUEST_ANT_PATTERN = "/{" + TENANT_PLACE_HOLDER
+ "}/controller/artifacts/v1/**"; + "}/controller/artifacts/v1/**";
protected TenantConfigurationManagement tenantConfigurationManagement;
protected TenantAware tenantAware;
protected SystemSecurityContext systemSecurityContext;
private final AntPathMatcher pathExtractor; private final AntPathMatcher pathExtractor;
private PreAuthenticationFilter abstractControllerAuthenticationFilter; private PreAuthenticationFilter abstractControllerAuthenticationFilter;
/** /**
* Constructor for subclasses. * Constructor for subclasses.
* *
* @param tenantConfigurationManagement the tenant configuration service * @param tenantConfigurationManagement the tenant configuration service
* @param tenantAware the tenant aware service * @param tenantAware the tenant aware service
* @param systemSecurityContext the system security context * @param systemSecurityContext the system security context
@@ -106,8 +103,6 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
} }
} }
protected abstract PreAuthenticationFilter createControllerAuthenticationFilter();
@Override @Override
protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response,
final Authentication authResult) throws IOException, ServletException { final Authentication authResult) throws IOException, ServletException {
@@ -120,11 +115,31 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
super.successfulAuthentication(request, response, authTokenWithGrantedAuthorities); super.successfulAuthentication(request, response, authTokenWithGrantedAuthorities);
} }
@Override
protected Object getPreAuthenticatedPrincipal(final HttpServletRequest request) {
final DmfTenantSecurityToken securityToken = createTenantSecurityTokenVariables(request);
if (securityToken == null) {
return null;
}
return abstractControllerAuthenticationFilter.getPreAuthenticatedPrincipal(securityToken);
}
@Override
protected Object getPreAuthenticatedCredentials(final HttpServletRequest request) {
final DmfTenantSecurityToken securityToken = createTenantSecurityTokenVariables(request);
if (securityToken == null) {
return null;
}
return abstractControllerAuthenticationFilter.getPreAuthenticatedCredentials(securityToken);
}
protected abstract PreAuthenticationFilter createControllerAuthenticationFilter();
protected abstract Logger log(); protected abstract Logger log();
/** /**
* Extracts tenant and controllerId from the request URI as path variables. * Extracts tenant and controllerId from the request URI as path variables.
* *
* @param request the Http request to extract the path variables. * @param request the Http request to extract the path variables.
* @return the extracted {@link DmfTenantSecurityToken} or {@code null} if the * @return the extracted {@link DmfTenantSecurityToken} or {@code null} if the
* request does not match the pattern and no variables could be * request does not match the pattern and no variables could be
@@ -150,13 +165,13 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
return createTenantSecurityTokenVariables(request, tenant, "anonymous"); return createTenantSecurityTokenVariables(request, tenant, "anonymous");
} else { } else {
log().trace("request {} does not match the path pattern {}, request gets ignored", requestURI, log().trace("request {} does not match the path pattern {}, request gets ignored", requestURI,
CONTROLLER_REQUEST_ANT_PATTERN); CONTROLLER_REQUEST_ANT_PATTERN);
return null; return null;
} }
} }
private DmfTenantSecurityToken createTenantSecurityTokenVariables(final HttpServletRequest request, private DmfTenantSecurityToken createTenantSecurityTokenVariables(final HttpServletRequest request,
final String tenant, final String controllerId) { final String tenant, final String controllerId) {
final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(tenant, null, controllerId, null); final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(tenant, null, controllerId, null);
Collections.list(request.getHeaderNames()) Collections.list(request.getHeaderNames())
@@ -165,22 +180,4 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
return securityToken; return securityToken;
} }
@Override
protected Object getPreAuthenticatedPrincipal(final HttpServletRequest request) {
final DmfTenantSecurityToken securityToken = createTenantSecurityTokenVariables(request);
if (securityToken == null) {
return null;
}
return abstractControllerAuthenticationFilter.getPreAuthenticatedPrincipal(securityToken);
}
@Override
protected Object getPreAuthenticatedCredentials(final HttpServletRequest request) {
final DmfTenantSecurityToken securityToken = createTenantSecurityTokenVariables(request);
if (securityToken == null) {
return null;
}
return abstractControllerAuthenticationFilter.getPreAuthenticatedCredentials(securityToken);
}
} }

View File

@@ -20,6 +20,8 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.util.IpUtil; import org.eclipse.hawkbit.util.IpUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -29,9 +31,6 @@ import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
/** /**
* Filter for protection against denial of service attacks. It reduces the * Filter for protection against denial of service attacks. It reduces the
* maximum number of request per seconds which can be separately configured for * maximum number of request per seconds which can be separately configured for
@@ -65,24 +64,17 @@ public class DosFilter extends OncePerRequestFilter {
/** /**
* Filter constructor including configuration. * Filter constructor including configuration.
*
* @param includeAntPaths
* paths where filter should hit
* *
* @param maxRead * @param includeAntPaths paths where filter should hit
* Maximum number of allowed REST read/GET requests per second * @param maxRead Maximum number of allowed REST read/GET requests per second
* per client * per client
* @param maxWrite * @param maxWrite Maximum number of allowed REST write/(PUT/POST/etc.) requests
* Maximum number of allowed REST write/(PUT/POST/etc.) requests * per second per client
* per second per client * @param ipDosWhiteListPattern {@link Pattern} with with white list of peer IP addresses for
* @param ipDosWhiteListPattern * DOS filter
* {@link Pattern} with with white list of peer IP addresses for * @param ipBlackListPattern {@link Pattern} with black listed IP addresses
* DOS filter * @param forwardHeader the header containing the forwarded IP address e.g.
* @param ipBlackListPattern * {@code x-forwarded-for}
* {@link Pattern} with black listed IP addresses
* @param forwardHeader
* the header containing the forwarded IP address e.g.
* {@code x-forwarded-for}
*/ */
public DosFilter(final Collection<String> includeAntPaths, final int maxRead, final int maxWrite, public DosFilter(final Collection<String> includeAntPaths, final int maxRead, final int maxWrite,
final String ipDosWhiteListPattern, final String ipBlackListPattern, final String forwardHeader) { final String ipDosWhiteListPattern, final String ipBlackListPattern, final String forwardHeader) {
@@ -104,15 +96,6 @@ public class DosFilter extends OncePerRequestFilter {
} }
} }
private boolean shouldInclude(final HttpServletRequest request) {
if (includeAntPaths == null || includeAntPaths.isEmpty()) {
return true;
}
return includeAntPaths.stream()
.anyMatch(pattern -> antMatcher.match(request.getContextPath() + pattern, request.getRequestURI()));
}
@Override @Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
final FilterChain filterChain) throws ServletException, IOException { final FilterChain filterChain) throws ServletException, IOException {
@@ -148,6 +131,25 @@ public class DosFilter extends OncePerRequestFilter {
} }
} }
private static boolean checkIpFails(final String ip) {
return ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip);
}
private static boolean handleMissingIpAddress(final HttpServletResponse response) {
log.error("Failed to get peer IP address");
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return false;
}
private boolean shouldInclude(final HttpServletRequest request) {
if (includeAntPaths == null || includeAntPaths.isEmpty()) {
return true;
}
return includeAntPaths.stream()
.anyMatch(pattern -> antMatcher.match(request.getContextPath() + pattern, request.getRequestURI()));
}
/** /**
* @return false if the given ip address is on the blacklist and further * @return false if the given ip address is on the blacklist and further
* processing of the request if forbidden * processing of the request if forbidden
@@ -161,16 +163,6 @@ public class DosFilter extends OncePerRequestFilter {
return true; return true;
} }
private static boolean checkIpFails(final String ip) {
return ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip);
}
private static boolean handleMissingIpAddress(final HttpServletResponse response) {
log.error("Failed to get peer IP address");
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return false;
}
private boolean handleWriteRequest(final HttpServletResponse response, final String ip) { private boolean handleWriteRequest(final HttpServletResponse response, final String ip) {
boolean processChain = true; boolean processChain = true;
final AtomicInteger count = writeCountCache.getIfPresent(ip); final AtomicInteger count = writeCountCache.getIfPresent(ip);

View File

@@ -26,7 +26,7 @@ public class HttpControllerPreAuthenticateAnonymousDownloadFilter extends Abstra
/** /**
* Constructor. * Constructor.
* *
* @param tenantConfigurationManagement the system management service to retrieve configuration properties * @param tenantConfigurationManagement the system management service to retrieve configuration properties
* @param tenantAware the tenant aware service to get configuration for the specific tenant * @param tenantAware the tenant aware service to get configuration for the specific tenant
* @param systemSecurityContext the system security context * @param systemSecurityContext the system security context

View File

@@ -21,7 +21,7 @@ import org.slf4j.Logger;
* security-token with the {@code Authorization} HTTP header. * security-token with the {@code Authorization} HTTP header.
* {@code Example Header: Authorization: TargetToken * {@code Example Header: Authorization: TargetToken
* 5d8fSD54fdsFG98DDsa.} * 5d8fSD54fdsFG98DDsa.}
* *
* The {@code Authorization} header is a HTTP standard and reverse proxy or * The {@code Authorization} header is a HTTP standard and reverse proxy or
* other proxies will keep the Authorization headers untouched instead of maybe * other proxies will keep the Authorization headers untouched instead of maybe
* custom headers which have then weird side-effects. Furthermore frameworks are * custom headers which have then weird side-effects. Furthermore frameworks are
@@ -35,18 +35,14 @@ public class HttpControllerPreAuthenticateSecurityTokenFilter extends AbstractHt
/** /**
* Constructor. * Constructor.
* *
* @param tenantConfigurationManagement * @param tenantConfigurationManagement the system management service to retrieve configuration
* the system management service to retrieve configuration * properties
* properties * @param tenantAware the tenant aware service to get configuration for the specific
* @param tenantAware * tenant
* the tenant aware service to get configuration for the specific * @param controllerManagement the controller management to retrieve the specific target
* tenant * security token to verify
* @param controllerManagement * @param systemSecurityContext the system security context
* the controller management to retrieve the specific target
* security token to verify
* @param systemSecurityContext
* the system security context
*/ */
public HttpControllerPreAuthenticateSecurityTokenFilter( public HttpControllerPreAuthenticateSecurityTokenFilter(
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,

View File

@@ -27,15 +27,12 @@ public class HttpControllerPreAuthenticatedGatewaySecurityTokenFilter
/** /**
* Constructor. * Constructor.
* *
* @param tenantConfigurationManagement * @param tenantConfigurationManagement the system management service to retrieve configuration
* the system management service to retrieve configuration * properties
* properties * @param tenantAware the tenant aware service to get configuration for the specific
* @param tenantAware * tenant
* the tenant aware service to get configuration for the specific * @param systemSecurityContext the system security context
* tenant
* @param systemSecurityContext
* the system security context
*/ */
public HttpControllerPreAuthenticatedGatewaySecurityTokenFilter( public HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware, final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,

View File

@@ -30,21 +30,16 @@ public class HttpControllerPreAuthenticatedSecurityHeaderFilter extends Abstract
* from the HTTP request with the given URI pattern, in case the URI pattern * 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 * does not match the current request then only the existence of the
* configured header field is checked. * configured header field is checked.
* *
* @param caCommonNameHeader * @param caCommonNameHeader the http-header which holds the common-name of the certificate
* the http-header which holds the common-name of the certificate * @param caAuthorityNameHeader the http-header which holds the ca-authority name of the
* @param caAuthorityNameHeader * certificate
* the http-header which holds the ca-authority name of the * @param tenantConfigurationManagement the tenant configuration management service to retrieve
* certificate * configuration properties to check if the header authentication
* @param tenantConfigurationManagement * is enabled for this tenant
* the tenant configuration management service to retrieve * @param tenantAware the tenant aware service to get configuration for the specific
* configuration properties to check if the header authentication * tenant
* is enabled for this tenant * @param systemSecurityContext the system security context
* @param tenantAware
* the tenant aware service to get configuration for the specific
* tenant
* @param systemSecurityContext
* the system security context
*/ */
public HttpControllerPreAuthenticatedSecurityHeaderFilter(final String caCommonNameHeader, public HttpControllerPreAuthenticatedSecurityHeaderFilter(final String caCommonNameHeader,
final String caAuthorityNameHeader, final TenantConfigurationManagement tenantConfigurationManagement, final String caAuthorityNameHeader, final TenantConfigurationManagement tenantConfigurationManagement,

View File

@@ -15,6 +15,9 @@ import static org.mockito.Mockito.when;
import java.util.Collections; import java.util.Collections;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
@@ -24,10 +27,6 @@ import org.springframework.security.authentication.InsufficientAuthenticationExc
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Unit Tests - Security") @Feature("Unit Tests - Security")
@Story("PreAuthToken Source TrustAuthentication Provider Test") @Story("PreAuthToken Source TrustAuthentication Provider Test")
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)