diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java index 0aaf7060a..5c75f2730 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java @@ -35,7 +35,6 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource; import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.DosFilter; -import org.eclipse.hawkbit.security.ExcludePathAwareShallowETagFilter; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateAnonymousDownloadFilter; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter; @@ -51,6 +50,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; @@ -172,6 +172,7 @@ public class SecurityManagedConfiguration { * of service protection filter in the filter chain */ @Bean + @ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true) public FilterRegistrationBean dosDDiFilter(final HawkbitSecurityProperties securityProperties) { final FilterRegistrationBean filterRegBean = dosFilter(Arrays.asList(DDI_ANT_MATCHER), @@ -262,6 +263,7 @@ public class SecurityManagedConfiguration { * service protection filter in the filter chain */ @Bean + @ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true) public FilterRegistrationBean dosSystemFilter(final HawkbitSecurityProperties securityProperties) { final FilterRegistrationBean filterRegBean = dosFilter(Collections.emptyList(), @@ -355,6 +357,7 @@ public class SecurityManagedConfiguration { * of service protection filter in the filter chain */ @Bean + @ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true) public FilterRegistrationBean dosMgmtFilter(final HawkbitSecurityProperties securityProperties) { final FilterRegistrationBean filterRegBean = dosFilter(null, securityProperties.getDos().getFilter(), @@ -406,29 +409,6 @@ public class SecurityManagedConfiguration { } } - /** - * Filter registration bean for spring etag filter. - * - * @return the spring filter registration bean for registering an etag - * filter in the filter chain - */ - @Bean - @Order(380) - public FilterRegistrationBean eTagFilter() { - - final FilterRegistrationBean filterRegBean = new FilterRegistrationBean(); - // Exclude the URLs for downloading artifacts, so no eTag is generated - // in the ShallowEtagHeaderFilter, just using the SH1 hash of the - // artifact itself as 'ETag', because otherwise the file will be copied - // in memory! - filterRegBean.setFilter(new ExcludePathAwareShallowETagFilter("/UI/**", - "/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", - "/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/**", - "/api/v1/downloadserver/**")); - - return filterRegBean; - } - /** * {@link WebSecurityConfigurer} for external (management) access. */ @@ -457,6 +437,7 @@ public class SecurityManagedConfiguration { * of service protection filter in the filter chain */ @Bean + @ConditionalOnProperty(prefix = "hawkbit.server.security.dos.ui-filter", name = "enabled", matchIfMissing = true) public FilterRegistrationBean dosMgmtUiFilter(final HawkbitSecurityProperties securityProperties) { final FilterRegistrationBean filterRegBean = dosFilter(null, securityProperties.getDos().getUiFilter(), diff --git a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java index b7db01219..3ec614020 100644 --- a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DosFilterTest.java @@ -19,9 +19,9 @@ import java.util.List; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.rest.filter.ExcludePathAwareShallowETagFilter; import org.eclipse.hawkbit.rest.util.JsonBuilder; import org.eclipse.hawkbit.security.DosFilter; -import org.eclipse.hawkbit.security.ExcludePathAwareShallowETagFilter; import org.junit.Test; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; diff --git a/hawkbit-http-security/pom.xml b/hawkbit-http-security/pom.xml index 283c6e603..b6597dbe8 100644 --- a/hawkbit-http-security/pom.xml +++ b/hawkbit-http-security/pom.xml @@ -39,6 +39,10 @@ javax.servlet javax.servlet-api provided + + + com.github.ben-manes.caffeine + caffeine diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java b/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/DosFilter.java similarity index 100% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java rename to hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/DosFilter.java diff --git a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/RestConfiguration.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/RestConfiguration.java index 896a4e09f..310172aa2 100644 --- a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/RestConfiguration.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/RestConfiguration.java @@ -11,10 +11,12 @@ package org.eclipse.hawkbit.rest; import javax.servlet.http.HttpServletResponse; import org.eclipse.hawkbit.rest.exception.ResponseExceptionHandler; +import org.eclipse.hawkbit.rest.filter.ExcludePathAwareShallowETagFilter; import org.eclipse.hawkbit.rest.util.FilterHttpResponse; import org.eclipse.hawkbit.rest.util.HttpResponseFactoryBean; import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; import org.springframework.beans.factory.FactoryBean; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @@ -64,4 +66,26 @@ public class RestConfiguration { ResponseExceptionHandler responseExceptionHandler() { return new ResponseExceptionHandler(); } + + /** + * Filter registration bean for spring etag filter. + * + * @return the spring filter registration bean for registering an etag + * filter in the filter chain + */ + @Bean + FilterRegistrationBean eTagFilter() { + + final FilterRegistrationBean filterRegBean = new FilterRegistrationBean(); + // Exclude the URLs for downloading artifacts, so no eTag is generated + // in the ShallowEtagHeaderFilter, just using the SH1 hash of the + // artifact itself as 'ETag', because otherwise the file will be copied + // in memory! + filterRegBean.setFilter(new ExcludePathAwareShallowETagFilter("/UI/**", + "/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", + "/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/**", + "/api/v1/downloadserver/**")); + + return filterRegBean; + } } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/ExcludePathAwareShallowETagFilter.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/filter/ExcludePathAwareShallowETagFilter.java similarity index 98% rename from hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/ExcludePathAwareShallowETagFilter.java rename to hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/filter/ExcludePathAwareShallowETagFilter.java index 3727902b4..bdbe053a7 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/ExcludePathAwareShallowETagFilter.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/filter/ExcludePathAwareShallowETagFilter.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.security; +package org.eclipse.hawkbit.rest.filter; import java.io.IOException; diff --git a/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java index 050d9c183..c147ea899 100644 --- a/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java @@ -10,8 +10,8 @@ package org.eclipse.hawkbit.rest; import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration; import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest; +import org.eclipse.hawkbit.rest.filter.ExcludePathAwareShallowETagFilter; import org.eclipse.hawkbit.rest.util.FilterHttpResponse; -import org.eclipse.hawkbit.security.ExcludePathAwareShallowETagFilter; import org.junit.Before; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/ExcludePathAwareShallowETagFilterTest.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/filter/ExcludePathAwareShallowETagFilterTest.java similarity index 96% rename from hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/ExcludePathAwareShallowETagFilterTest.java rename to hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/filter/ExcludePathAwareShallowETagFilterTest.java index 4dedf3171..96161491e 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/ExcludePathAwareShallowETagFilterTest.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/filter/ExcludePathAwareShallowETagFilterTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.security; +package org.eclipse.hawkbit.rest.filter; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mockingDetails; @@ -21,6 +21,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.hawkbit.rest.filter.ExcludePathAwareShallowETagFilter; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; diff --git a/hawkbit-security-core/pom.xml b/hawkbit-security-core/pom.xml index 4da03404f..91493a78e 100644 --- a/hawkbit-security-core/pom.xml +++ b/hawkbit-security-core/pom.xml @@ -31,14 +31,6 @@ javax.servlet-api provided - - org.springframework - spring-web - - - com.github.ben-manes.caffeine - caffeine - org.slf4j slf4j-api diff --git a/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 index d51435d4b..de2ab6d4f 100644 --- a/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 @@ -159,10 +159,15 @@ public class HawkbitSecurityProperties { /** * Configuration for hawkBits DOS prevention filter. This is usually an - * infrastructure topic but might be useful in some cases. + * infrastructure topic (e.g. Web Application Firewall (WAF)) but might + * be useful in some cases, e.g. to prevent unintended misuse. * */ public static class Filter { + /** + * True if filter is enabled. + */ + private boolean enabled = true; /** * White list of peer IP addresses for DOS filter (regular @@ -172,16 +177,24 @@ public class HawkbitSecurityProperties { /** * # Maximum number of allowed REST read/GET requests per second per - * client. + * client IP. */ int maxRead = 200; /** * Maximum number of allowed REST write/(PUT/POST/etc.) requests per - * second per client. + * second per client IP. */ int maxWrite = 50; + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + public String getWhitelist() { return whitelist; }