Extract a SecurityFilterChain interface and create a default implementation to facilitate other configuration options.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package org.springframework.security.web;
|
||||
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Standard implementation of {@code SecurityFilterChain}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class DefaultSecurityFilterChain implements SecurityFilterChain {
|
||||
private final RequestMatcher requestMatcher;
|
||||
private final List<Filter> filters;
|
||||
|
||||
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
|
||||
this(requestMatcher, Arrays.asList(filters));
|
||||
}
|
||||
|
||||
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
|
||||
this.requestMatcher = requestMatcher;
|
||||
this.filters = new ArrayList<Filter>(filters);
|
||||
}
|
||||
|
||||
public RequestMatcher getRequestMatcher() {
|
||||
return requestMatcher;
|
||||
}
|
||||
|
||||
public List<Filter> getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return requestMatcher.matches(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[ " + requestMatcher + ", " + filters + "]";
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,6 @@ public class FilterChainProxy extends GenericFilterBean {
|
||||
|
||||
public FilterChainProxy(List<SecurityFilterChain> filterChains) {
|
||||
this.filterChains = filterChains;
|
||||
checkPathOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -219,10 +218,8 @@ public class FilterChainProxy extends GenericFilterBean {
|
||||
filterChains = new ArrayList<SecurityFilterChain>(filterChainMap.size());
|
||||
|
||||
for (Map.Entry<RequestMatcher,List<Filter>> entry : filterChainMap.entrySet()) {
|
||||
filterChains.add(new SecurityFilterChain(entry.getKey(), entry.getValue()));
|
||||
filterChains.add(new DefaultSecurityFilterChain(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
|
||||
checkPathOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,25 +235,12 @@ public class FilterChainProxy extends GenericFilterBean {
|
||||
LinkedHashMap<RequestMatcher, List<Filter>> map = new LinkedHashMap<RequestMatcher, List<Filter>>();
|
||||
|
||||
for (SecurityFilterChain chain : filterChains) {
|
||||
map.put(chain.getRequestMatcher(), chain.getFilters());
|
||||
map.put(((DefaultSecurityFilterChain)chain).getRequestMatcher(), chain.getFilters());
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private void checkPathOrder() {
|
||||
// Check that the universal pattern is listed at the end, if at all
|
||||
Iterator<SecurityFilterChain> chains = filterChains.iterator();
|
||||
|
||||
while(chains.hasNext()) {
|
||||
if ((chains.next().getRequestMatcher() instanceof AnyRequestMatcher && chains.hasNext())) {
|
||||
throw new IllegalArgumentException("A universal match pattern ('/**') is defined " +
|
||||
" before other patterns in the filter chain, causing them to be ignored. Please check the " +
|
||||
"ordering in your <security:http> namespace or FilterChainProxy bean configuration");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of {@code SecurityFilterChain}s which will be matched against and
|
||||
* applied to incoming requests.
|
||||
|
||||
@@ -1,54 +1,23 @@
|
||||
package org.springframework.security.web;
|
||||
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Bean which defines a filter chain which is capable of being matched against an {@code HttpServletRequest}.
|
||||
* Defines a filter chain which is capable of being matched against an {@code HttpServletRequest}.
|
||||
* in order to decide whether it applies to that request.
|
||||
* <p>
|
||||
* Used to configure a {@code FilterChainProxy}.
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class SecurityFilterChain {
|
||||
private final RequestMatcher requestMatcher;
|
||||
private final List<Filter> filters;
|
||||
public interface SecurityFilterChain {
|
||||
|
||||
public SecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
|
||||
this(requestMatcher, Arrays.asList(filters));
|
||||
}
|
||||
boolean matches(HttpServletRequest request);
|
||||
|
||||
public SecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
|
||||
this.requestMatcher = requestMatcher;
|
||||
this.filters = new ArrayList<Filter>(filters);
|
||||
}
|
||||
|
||||
public RequestMatcher getRequestMatcher() {
|
||||
return requestMatcher;
|
||||
}
|
||||
|
||||
public List<Filter> getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return requestMatcher.matches(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[ " + requestMatcher + ", " + filters + "]";
|
||||
}
|
||||
List<Filter> getFilters();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class FilterChainProxyTests {
|
||||
return null;
|
||||
}
|
||||
}).when(filter).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class), any(FilterChain.class));
|
||||
fcp = new FilterChainProxy(new SecurityFilterChain(matcher, Arrays.asList(filter)));
|
||||
fcp = new FilterChainProxy(new DefaultSecurityFilterChain(matcher, Arrays.asList(filter)));
|
||||
fcp.setFilterChainValidator(mock(FilterChainProxy.FilterChainValidator.class));
|
||||
request = new MockHttpServletRequest();
|
||||
request.setServletPath("/path");
|
||||
@@ -94,7 +94,7 @@ public class FilterChainProxyTests {
|
||||
@Test
|
||||
public void originalFilterChainIsInvokedIfMatchingSecurityChainIsEmpty() throws Exception {
|
||||
List<Filter> noFilters = Collections.emptyList();
|
||||
fcp = new FilterChainProxy(new SecurityFilterChain(matcher, noFilters));
|
||||
fcp = new FilterChainProxy(new DefaultSecurityFilterChain(matcher, noFilters));
|
||||
|
||||
when(matcher.matches(any(HttpServletRequest.class))).thenReturn(true);
|
||||
fcp.doFilter(request, response, chain);
|
||||
@@ -137,7 +137,7 @@ public class FilterChainProxyTests {
|
||||
@Test
|
||||
public void bothWrappersAreResetWithNestedFcps() throws Exception {
|
||||
HttpFirewall fw = mock(HttpFirewall.class);
|
||||
FilterChainProxy firstFcp = new FilterChainProxy(new SecurityFilterChain(matcher, fcp));
|
||||
FilterChainProxy firstFcp = new FilterChainProxy(new DefaultSecurityFilterChain(matcher, fcp));
|
||||
firstFcp.setFirewall(fw);
|
||||
fcp.setFirewall(fw);
|
||||
FirewalledRequest firstFwr = mock(FirewalledRequest.class, "firstFwr");
|
||||
|
||||
Reference in New Issue
Block a user