Skip to content

Commit

Permalink
Add MvcRequestMatcher
Browse files Browse the repository at this point in the history
Fixes gh-3964
  • Loading branch information
Rob Winch committed Jul 6, 2016
1 parent 13bc70f commit e4c13e3
Show file tree
Hide file tree
Showing 26 changed files with 918 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.util.Assert;
import org.springframework.web.filter.DelegatingFilterProxy;
Expand Down Expand Up @@ -57,7 +58,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<SecurityConfigurer<O, B>>();

private final Map<Class<Object>, Object> sharedObjects = new HashMap<Class<Object>, Object>();
private final Map<Class<? extends Object>, Object> sharedObjects = new HashMap<Class<? extends Object>, Object>();

private final boolean allowConfigurersOfSameType;

Expand Down Expand Up @@ -155,7 +156,7 @@ public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Excepti
*/
@SuppressWarnings("unchecked")
public <C> void setSharedObject(Class<C> sharedType, C object) {
this.sharedObjects.put((Class<Object>) sharedType, object);
this.sharedObjects.put(sharedType, object);
}

/**
Expand All @@ -173,7 +174,7 @@ public <C> C getSharedObject(Class<C> sharedType) {
* Gets the shared objects
* @return
*/
public Map<Class<Object>, Object> getSharedObjects() {
public Map<Class<? extends Object>, Object> getSharedObjects() {
return Collections.unmodifiableMap(this.sharedObjects);
}

Expand Down Expand Up @@ -300,7 +301,7 @@ public O objectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
* @return the possibly modified Object to use
*/
protected <P> P postProcess(P object) {
return (P) this.objectPostProcessor.postProcess(object);
return this.objectPostProcessor.postProcess(object);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
import java.util.Arrays;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

/**
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for
Expand All @@ -39,6 +42,12 @@
public abstract class AbstractRequestMatcherRegistry<C> {
private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE;

private ApplicationContext context;

protected final void setApplicationContext(ApplicationContext context) {
this.context = context;
}

/**
* Maps any request.
*
Expand Down Expand Up @@ -92,6 +101,57 @@ public C antMatchers(String... antPatterns) {
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
}

/**
* <p>
* Maps an {@link MvcRequestMatcher} that does not care which {@link HttpMethod} is
* used. This matcher will use the same rules that Spring MVC uses for matching. For
* example, often times a mapping of the path "/path" will match on "/path", "/path/",
* "/path.html", etc.
* </p>
* <p>
* If the current request will not be processed by Spring MVC, a reasonable default
* using the pattern as a ant pattern will be used.
* </p>
*
* @param mvcPatterns the patterns to match on. The rules for matching are defined by
* Spring MVC
* @return the object that is chained after creating the {@link RequestMatcher}.
*/
public C mvcMatchers(String... mvcPatterns) {
return mvcMatchers(null, mvcPatterns);
}

/**
* <p>
* Maps an {@link MvcRequestMatcher} that also specifies a specific {@link HttpMethod}
* to match on. This matcher will use the same rules that Spring MVC uses for
* matching. For example, often times a mapping of the path "/path" will match on
* "/path", "/path/", "/path.html", etc.
* </p>
* <p>
* If the current request will not be processed by Spring MVC, a reasonable default
* using the pattern as a ant pattern will be used.
* </p>
*
* @param method the HTTP method to match on
* @param mvcPatterns the patterns to match on. The rules for matching are defined by
* Spring MVC
* @return the object that is chained after creating the {@link RequestMatcher}.
*/
public C mvcMatchers(HttpMethod method, String... mvcPatterns) {
HandlerMappingIntrospector introspector = new HandlerMappingIntrospector(
this.context);
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>(mvcPatterns.length);
for (String mvcPattern : mvcPatterns) {
MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
if (method != null) {
matcher.setMethod(method);
}
matchers.add(matcher);
}
return chainRequestMatchers(matchers);
}

/**
* Maps a {@link List} of
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;

import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
Expand Down Expand Up @@ -62,6 +63,7 @@
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.PortMapperImpl;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
Expand Down Expand Up @@ -113,7 +115,7 @@ public final class HttpSecurity extends
AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>,
HttpSecurityBuilder<HttpSecurity> {
private final RequestMatcherConfigurer requestMatcherConfigurer = new RequestMatcherConfigurer();
private final RequestMatcherConfigurer requestMatcherConfigurer;
private List<Filter> filters = new ArrayList<Filter>();
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
private FilterComparator comparator = new FilterComparator();
Expand All @@ -126,15 +128,24 @@ public final class HttpSecurity extends
* @param sharedObjects the shared Objects to initialize the {@link HttpSecurity} with
* @see WebSecurityConfiguration
*/
@SuppressWarnings("unchecked")
public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor,
AuthenticationManagerBuilder authenticationBuilder,
Map<Class<Object>, Object> sharedObjects) {
Map<Class<? extends Object>, Object> sharedObjects) {
super(objectPostProcessor);
Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null");
setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder);
for (Map.Entry<Class<Object>, Object> entry : sharedObjects.entrySet()) {
setSharedObject(entry.getKey(), entry.getValue());
for (Map.Entry<Class<? extends Object>, Object> entry : sharedObjects
.entrySet()) {
setSharedObject((Class<Object>) entry.getKey(), entry.getValue());
}
ApplicationContext context = (ApplicationContext) sharedObjects
.get(ApplicationContext.class);
this.requestMatcherConfigurer = new RequestMatcherConfigurer(context);
}

private ApplicationContext getContext() {
return getSharedObject(ApplicationContext.class);
}

/**
Expand Down Expand Up @@ -634,7 +645,8 @@ public RememberMeConfigurer<HttpSecurity> rememberMe() throws Exception {
*/
public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests()
throws Exception {
return getOrApply(new ExpressionUrlAuthorizationConfigurer<HttpSecurity>())
ApplicationContext context = getContext();
return getOrApply(new ExpressionUrlAuthorizationConfigurer<HttpSecurity>(context))
.getRegistry();
}

Expand Down Expand Up @@ -710,7 +722,8 @@ public ServletApiConfigurer<HttpSecurity> servletApi() throws Exception {
* @throws Exception
*/
public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
return getOrApply(new CsrfConfigurer<HttpSecurity>());
ApplicationContext context = getContext();
return getOrApply(new CsrfConfigurer<HttpSecurity>(context));
}

/**
Expand Down Expand Up @@ -917,7 +930,9 @@ public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
*/
public ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry requiresChannel()
throws Exception {
return getOrApply(new ChannelSecurityConfigurer<HttpSecurity>()).getRegistry();
ApplicationContext context = getContext();
return getOrApply(new ChannelSecurityConfigurer<HttpSecurity>(context))
.getRegistry();
}

/**
Expand Down Expand Up @@ -1241,8 +1256,16 @@ public HttpSecurity regexMatcher(String pattern) {
*/
public final class RequestMatcherConfigurer extends
AbstractRequestMatcherRegistry<RequestMatcherConfigurer> {

private List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();

/**
* @param context
*/
private RequestMatcherConfigurer(ApplicationContext context) {
setApplicationContext(context);
}

protected RequestMatcherConfigurer chainRequestMatchers(
List<RequestMatcher> requestMatchers) {
matchers.addAll(requestMatchers);
Expand All @@ -1259,8 +1282,6 @@ public HttpSecurity and() {
return HttpSecurity.this;
}

private RequestMatcherConfigurer() {
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
Expand Down Expand Up @@ -80,7 +81,7 @@ public final class WebSecurity extends

private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<SecurityBuilder<? extends SecurityFilterChain>>();

private final IgnoredRequestConfigurer ignoredRequestRegistry = new IgnoredRequestConfigurer();
private IgnoredRequestConfigurer ignoredRequestRegistry;

private FilterSecurityInterceptor filterSecurityInterceptor;

Expand Down Expand Up @@ -316,6 +317,10 @@ protected Filter performBuild() throws Exception {
public final class IgnoredRequestConfigurer extends
AbstractRequestMatcherRegistry<IgnoredRequestConfigurer> {

private IgnoredRequestConfigurer(ApplicationContext context) {
setApplicationContext(context);
}

@Override
protected IgnoredRequestConfigurer chainRequestMatchers(
List<RequestMatcher> requestMatchers) {
Expand All @@ -329,13 +334,13 @@ protected IgnoredRequestConfigurer chainRequestMatchers(
public WebSecurity and() {
return WebSecurity.this;
}

private IgnoredRequestConfigurer() {
}
}

@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
defaultWebSecurityExpressionHandler.setApplicationContext(applicationContext);
this.defaultWebSecurityExpressionHandler
.setApplicationContext(applicationContext);
this.ignoredRequestRegistry = new IgnoredRequestConfigurer(applicationContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,14 @@ protected void configure(HttpSecurity http) throws Exception {
}
// @formatter:on

/**
* Gets the ApplicationContext
* @return the context
*/
protected final ApplicationContext getApplicationContext() {
return this.context;
}

@Autowired
public void setApplicationContext(ApplicationContext context) {
this.context = context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.LinkedHashMap;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.config.annotation.ObjectPostProcessor;
Expand Down Expand Up @@ -80,13 +81,14 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
private LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
private List<ChannelProcessor> channelProcessors;

private final ChannelRequestMatcherRegistry REGISTRY = new ChannelRequestMatcherRegistry();
private final ChannelRequestMatcherRegistry REGISTRY;

/**
* Creates a new instance
* @see HttpSecurity#requiresChannel()
*/
public ChannelSecurityConfigurer() {
public ChannelSecurityConfigurer(ApplicationContext context) {
this.REGISTRY = new ChannelRequestMatcherRegistry(context);
}

public ChannelRequestMatcherRegistry getRegistry() {
Expand Down Expand Up @@ -146,6 +148,10 @@ private ChannelRequestMatcherRegistry addAttribute(String attribute,
public final class ChannelRequestMatcherRegistry extends
AbstractConfigAttributeRequestMatcherRegistry<RequiresChannelUrl> {

private ChannelRequestMatcherRegistry(ApplicationContext context) {
setApplicationContext(context);
}

@Override
protected RequiresChannelUrl chainRequestMatchersInternal(
List<RequestMatcher> requestMatchers) {
Expand Down Expand Up @@ -185,9 +191,6 @@ public ChannelRequestMatcherRegistry channelProcessors(
public H and() {
return ChannelSecurityConfigurer.this.and();
}

private ChannelRequestMatcherRegistry() {
}
}

public final class RequiresChannelUrl {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import javax.servlet.http.HttpServletRequest;

import org.springframework.context.ApplicationContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
Expand Down Expand Up @@ -78,12 +79,14 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
new HttpSessionCsrfTokenRepository());
private RequestMatcher requireCsrfProtectionMatcher = CsrfFilter.DEFAULT_CSRF_MATCHER;
private List<RequestMatcher> ignoredCsrfProtectionMatchers = new ArrayList<RequestMatcher>();
private final ApplicationContext context;

/**
* Creates a new instance
* @see HttpSecurity#csrf()
*/
public CsrfConfigurer() {
public CsrfConfigurer(ApplicationContext context) {
this.context = context;
}

/**
Expand Down Expand Up @@ -141,7 +144,8 @@ public CsrfConfigurer<H> requireCsrfProtectionMatcher(
* @since 4.0
*/
public CsrfConfigurer<H> ignoringAntMatchers(String... antPatterns) {
return new IgnoreCsrfProtectionRegistry().antMatchers(antPatterns).and();
return new IgnoreCsrfProtectionRegistry(this.context).antMatchers(antPatterns)
.and();
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -265,6 +269,13 @@ private AccessDeniedHandler createAccessDeniedHandler(H http) {
private class IgnoreCsrfProtectionRegistry
extends AbstractRequestMatcherRegistry<IgnoreCsrfProtectionRegistry> {

/**
* @param context
*/
private IgnoreCsrfProtectionRegistry(ApplicationContext context) {
setApplicationContext(context);
}

public CsrfConfigurer<H> and() {
return CsrfConfigurer.this;
}
Expand Down
Loading

0 comments on commit e4c13e3

Please sign in to comment.