DosFilter can be disabled. (#561)
* DosFilter can be disabled. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Moved filters our of security core. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Move caffeine dependency. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -35,7 +35,6 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
|||||||
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
|
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
|
||||||
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||||
import org.eclipse.hawkbit.security.DosFilter;
|
import org.eclipse.hawkbit.security.DosFilter;
|
||||||
import org.eclipse.hawkbit.security.ExcludePathAwareShallowETagFilter;
|
|
||||||
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||||
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateAnonymousDownloadFilter;
|
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateAnonymousDownloadFilter;
|
||||||
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter;
|
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter;
|
||||||
@@ -51,6 +50,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
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.autoconfigure.security.SecurityProperties;
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
|
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
|
||||||
@@ -172,6 +172,7 @@ public class SecurityManagedConfiguration {
|
|||||||
* of service protection filter in the filter chain
|
* of service protection filter in the filter chain
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true)
|
||||||
public FilterRegistrationBean dosDDiFilter(final HawkbitSecurityProperties securityProperties) {
|
public FilterRegistrationBean dosDDiFilter(final HawkbitSecurityProperties securityProperties) {
|
||||||
|
|
||||||
final FilterRegistrationBean filterRegBean = dosFilter(Arrays.asList(DDI_ANT_MATCHER),
|
final FilterRegistrationBean filterRegBean = dosFilter(Arrays.asList(DDI_ANT_MATCHER),
|
||||||
@@ -262,6 +263,7 @@ public class SecurityManagedConfiguration {
|
|||||||
* service protection filter in the filter chain
|
* service protection filter in the filter chain
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true)
|
||||||
public FilterRegistrationBean dosSystemFilter(final HawkbitSecurityProperties securityProperties) {
|
public FilterRegistrationBean dosSystemFilter(final HawkbitSecurityProperties securityProperties) {
|
||||||
|
|
||||||
final FilterRegistrationBean filterRegBean = dosFilter(Collections.emptyList(),
|
final FilterRegistrationBean filterRegBean = dosFilter(Collections.emptyList(),
|
||||||
@@ -355,6 +357,7 @@ public class SecurityManagedConfiguration {
|
|||||||
* of service protection filter in the filter chain
|
* of service protection filter in the filter chain
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true)
|
||||||
public FilterRegistrationBean dosMgmtFilter(final HawkbitSecurityProperties securityProperties) {
|
public FilterRegistrationBean dosMgmtFilter(final HawkbitSecurityProperties securityProperties) {
|
||||||
|
|
||||||
final FilterRegistrationBean filterRegBean = dosFilter(null, securityProperties.getDos().getFilter(),
|
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.
|
* {@link WebSecurityConfigurer} for external (management) access.
|
||||||
*/
|
*/
|
||||||
@@ -457,6 +437,7 @@ public class SecurityManagedConfiguration {
|
|||||||
* of service protection filter in the filter chain
|
* of service protection filter in the filter chain
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.ui-filter", name = "enabled", matchIfMissing = true)
|
||||||
public FilterRegistrationBean dosMgmtUiFilter(final HawkbitSecurityProperties securityProperties) {
|
public FilterRegistrationBean dosMgmtUiFilter(final HawkbitSecurityProperties securityProperties) {
|
||||||
|
|
||||||
final FilterRegistrationBean filterRegBean = dosFilter(null, securityProperties.getDos().getUiFilter(),
|
final FilterRegistrationBean filterRegBean = dosFilter(null, securityProperties.getDos().getUiFilter(),
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ import java.util.List;
|
|||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
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.rest.util.JsonBuilder;
|
||||||
import org.eclipse.hawkbit.security.DosFilter;
|
import org.eclipse.hawkbit.security.DosFilter;
|
||||||
import org.eclipse.hawkbit.security.ExcludePathAwareShallowETagFilter;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
|||||||
@@ -39,6 +39,10 @@
|
|||||||
<groupId>javax.servlet</groupId>
|
<groupId>javax.servlet</groupId>
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ package org.eclipse.hawkbit.rest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.rest.exception.ResponseExceptionHandler;
|
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.FilterHttpResponse;
|
||||||
import org.eclipse.hawkbit.rest.util.HttpResponseFactoryBean;
|
import org.eclipse.hawkbit.rest.util.HttpResponseFactoryBean;
|
||||||
import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder;
|
import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
@@ -64,4 +66,26 @@ public class RestConfiguration {
|
|||||||
ResponseExceptionHandler responseExceptionHandler() {
|
ResponseExceptionHandler responseExceptionHandler() {
|
||||||
return new 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
* http://www.eclipse.org/legal/epl-v10.html
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.security;
|
package org.eclipse.hawkbit.rest.filter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -10,8 +10,8 @@ package org.eclipse.hawkbit.rest;
|
|||||||
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||||
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
|
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.rest.util.FilterHttpResponse;
|
||||||
import org.eclipse.hawkbit.security.ExcludePathAwareShallowETagFilter;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
* http://www.eclipse.org/legal/epl-v10.html
|
* 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.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mockingDetails;
|
import static org.mockito.Mockito.mockingDetails;
|
||||||
@@ -21,6 +21,7 @@ import javax.servlet.ServletException;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.rest.filter.ExcludePathAwareShallowETagFilter;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
@@ -31,14 +31,6 @@
|
|||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
|
||||||
<artifactId>caffeine</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
|||||||
@@ -159,10 +159,15 @@ public class HawkbitSecurityProperties {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for hawkBits DOS prevention filter. This is usually an
|
* 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 {
|
public static class Filter {
|
||||||
|
/**
|
||||||
|
* True if filter is enabled.
|
||||||
|
*/
|
||||||
|
private boolean enabled = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* White list of peer IP addresses for DOS filter (regular
|
* 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
|
* # Maximum number of allowed REST read/GET requests per second per
|
||||||
* client.
|
* client IP.
|
||||||
*/
|
*/
|
||||||
int maxRead = 200;
|
int maxRead = 200;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of allowed REST write/(PUT/POST/etc.) requests per
|
* Maximum number of allowed REST write/(PUT/POST/etc.) requests per
|
||||||
* second per client.
|
* second per client IP.
|
||||||
*/
|
*/
|
||||||
int maxWrite = 50;
|
int maxWrite = 50;
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(final boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
public String getWhitelist() {
|
public String getWhitelist() {
|
||||||
return whitelist;
|
return whitelist;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user