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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.rest.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.filter.ShallowEtagHeaderFilter;
|
||||
|
||||
/**
|
||||
* An {@link ShallowEtagHeaderFilter} with exclusion paths to exclude some paths
|
||||
* where no ETag header should be generated due that calculating the ETag is an
|
||||
* expensive operation and the response output need to be copied in memory which
|
||||
* should be excluded in case of artifact downloads which could be big of size.
|
||||
*/
|
||||
public class ExcludePathAwareShallowETagFilter extends ShallowEtagHeaderFilter {
|
||||
|
||||
private final String[] excludeAntPaths;
|
||||
private final AntPathMatcher antMatcher = new AntPathMatcher();
|
||||
|
||||
/**
|
||||
* @param excludeAntPaths
|
||||
*/
|
||||
public ExcludePathAwareShallowETagFilter(final String... excludeAntPaths) {
|
||||
this.excludeAntPaths = excludeAntPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
|
||||
final FilterChain filterChain) throws ServletException, IOException {
|
||||
final boolean shouldExclude = shouldExclude(request);
|
||||
if (shouldExclude) {
|
||||
filterChain.doFilter(request, response);
|
||||
} else {
|
||||
super.doFilterInternal(request, response, filterChain);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldExclude(final HttpServletRequest request) {
|
||||
for (final String pattern : excludeAntPaths) {
|
||||
if (antMatcher.match(request.getContextPath() + pattern, request.getRequestURI())) {
|
||||
// exclude this request from eTag filter
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.rest.filter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mockingDetails;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
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;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Unit Tests - Security")
|
||||
@Stories("Exclude path aware shallow ETag filter")
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ExcludePathAwareShallowETagFilterTest {
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest servletRequestMock;
|
||||
|
||||
@Mock
|
||||
private HttpServletResponse servletResponseMock;
|
||||
|
||||
@Mock
|
||||
private FilterChain filterChainMock;
|
||||
|
||||
@Test
|
||||
public void excludePathDoesNotCalculateETag() throws ServletException, IOException {
|
||||
final String knownContextPath = "/bumlux/test";
|
||||
final String knownUri = knownContextPath + "/exclude/download";
|
||||
final String antPathExclusion = "/exclude/**";
|
||||
|
||||
// mock
|
||||
when(servletRequestMock.getContextPath()).thenReturn(knownContextPath);
|
||||
when(servletRequestMock.getRequestURI()).thenReturn(knownUri);
|
||||
|
||||
final ExcludePathAwareShallowETagFilter filterUnderTest = new ExcludePathAwareShallowETagFilter(
|
||||
antPathExclusion);
|
||||
|
||||
filterUnderTest.doFilterInternal(servletRequestMock, servletResponseMock, filterChainMock);
|
||||
|
||||
// verify no eTag header is set and response has not been changed
|
||||
assertThat(servletResponseMock.getHeader("ETag"))
|
||||
.as("ETag header should not be set during downloading, too expensive").isNull();
|
||||
// the servlet response must be the same mock!
|
||||
verify(filterChainMock, times(1)).doFilter(servletRequestMock, servletResponseMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathNotExcludedETagIsCalculated() throws ServletException, IOException {
|
||||
final String knownContextPath = "/bumlux/test";
|
||||
final String knownUri = knownContextPath + "/include/download";
|
||||
final String antPathExclusion = "/exclude/**";
|
||||
|
||||
// mock
|
||||
when(servletRequestMock.getContextPath()).thenReturn(knownContextPath);
|
||||
when(servletRequestMock.getRequestURI()).thenReturn(knownUri);
|
||||
|
||||
final ExcludePathAwareShallowETagFilter filterUnderTest = new ExcludePathAwareShallowETagFilter(
|
||||
antPathExclusion);
|
||||
|
||||
final ArgumentCaptor<HttpServletResponse> responseArgumentCaptor = ArgumentCaptor
|
||||
.forClass(HttpServletResponse.class);
|
||||
|
||||
filterUnderTest.doFilterInternal(servletRequestMock, servletResponseMock, filterChainMock);
|
||||
|
||||
// the servlet response must be the same mock!
|
||||
verify(filterChainMock, times(1)).doFilter(Mockito.eq(servletRequestMock), responseArgumentCaptor.capture());
|
||||
assertThat(mockingDetails(responseArgumentCaptor.getValue()).isMock()).isFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user