Pārlūkot izejas kodu

Use AuthorizationManager in <http>

Closes gh-11305
Josh Cummings 3 gadi atpakaļ
vecāks
revīzija
9dbd1f3e25
22 mainītis faili ar 1034 papildinājumiem un 30 dzēšanām
  1. 188 0
      config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java
  2. 35 1
      config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java
  3. 6 0
      config/src/main/resources/org/springframework/security/config/spring-security-5.8.rnc
  4. 43 29
      config/src/main/resources/org/springframework/security/config/spring-security-5.8.xsd
  5. 30 0
      config/src/test/java/org/springframework/security/config/http/HttpConfigTests.java
  6. 183 0
      config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java
  7. 36 0
      config/src/test/resources/org/springframework/security/config/http/HttpConfigTests-AuthorizationManager.xml
  8. 32 0
      config/src/test/resources/org/springframework/security/config/http/HttpConfigTests-MinimalAuthorizationManager.xml
  9. 33 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-AntMatcherServletPathAuthorizationManager.xml
  10. 36 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariablesAuthorizationManager.xml
  11. 33 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CiRegexMatcherServletPathAuthorizationManager.xml
  12. 33 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPathAuthorizationManager.xml
  13. 35 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-HasAnyRoleAuthorizationManager.xml
  14. 42 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersAuthorizationManager.xml
  15. 41 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersPathVariablesAuthorizationManager.xml
  16. 42 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPathAuthorizationManager.xml
  17. 36 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethodAuthorizationManager.xml
  18. 36 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariablesAuthorizationManager.xml
  19. 33 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-RegexMatcherServletPathAuthorizationManager.xml
  20. 37 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256AuthorizationManager.xml
  21. 37 0
      config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariablesAuthorizationManager.xml
  22. 7 0
      docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc

+ 188 - 0
config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java

@@ -0,0 +1,188 @@
+/*
+ * Copyright 2002-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.config.http;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.w3c.dom.Element;
+
+import org.springframework.beans.BeanMetadataElement;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.beans.factory.xml.XmlReaderContext;
+import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
+import org.springframework.security.authorization.AuthorizationManager;
+import org.springframework.security.config.Elements;
+import org.springframework.security.web.access.expression.DefaultHttpSecurityExpressionHandler;
+import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
+import org.springframework.security.web.access.intercept.AuthorizationFilter;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
+import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
+import org.springframework.security.web.util.matcher.AnyRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
+
+/**
+ * Allows for convenient creation of a {@link FilterInvocationSecurityMetadataSource} bean
+ * for use with a FilterSecurityInterceptor.
+ *
+ * @author Luke Taylor
+ */
+public class AuthorizationFilterParser implements BeanDefinitionParser {
+
+	private static final String ATT_USE_EXPRESSIONS = "use-expressions";
+
+	private static final String ATT_HTTP_METHOD = "method";
+
+	private static final String ATT_PATTERN = "pattern";
+
+	private static final String ATT_ACCESS = "access";
+
+	private static final String ATT_SERVLET_PATH = "servlet-path";
+
+	private String authorizationManagerRef;
+
+	@Override
+	public BeanDefinition parse(Element element, ParserContext parserContext) {
+		if (!isUseExpressions(element)) {
+			parserContext.getReaderContext().error("AuthorizationManager must be used with `use-expressions=\"true\"",
+					element);
+			return null;
+		}
+		this.authorizationManagerRef = createAuthorizationManager(element, parserContext);
+		BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(AuthorizationFilter.class);
+		filterBuilder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
+		BeanDefinition filter = filterBuilder.addConstructorArgReference(this.authorizationManagerRef)
+				.getBeanDefinition();
+		String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
+		if (StringUtils.hasText(id)) {
+			parserContext.registerComponent(new BeanComponentDefinition(filter, id));
+			parserContext.getRegistry().registerBeanDefinition(id, filter);
+		}
+		return filter;
+	}
+
+	public String getAuthorizationManagerRef() {
+		return this.authorizationManagerRef;
+	}
+
+	private String createAuthorizationManager(Element element, ParserContext parserContext) {
+		XmlReaderContext context = parserContext.getReaderContext();
+		String authorizationManagerRef = element.getAttribute("authorization-manager-ref");
+		if (StringUtils.hasText(authorizationManagerRef)) {
+			return authorizationManagerRef;
+		}
+		Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER);
+		String expressionHandlerRef = (expressionHandlerElt != null) ? expressionHandlerElt.getAttribute("ref") : null;
+		if (expressionHandlerRef == null) {
+			expressionHandlerRef = registerDefaultExpressionHandler(parserContext);
+		}
+		MatcherType matcherType = MatcherType.fromElement(element);
+		ManagedMap<BeanMetadataElement, BeanDefinition> matcherToExpression = new ManagedMap<>();
+		List<Element> interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
+		for (Element interceptMessage : interceptMessages) {
+			String accessExpression = interceptMessage.getAttribute(ATT_ACCESS);
+			BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder
+					.rootBeanDefinition(WebExpressionAuthorizationManager.class);
+			authorizationManager.addPropertyReference("expressionHandler", expressionHandlerRef);
+			authorizationManager.addConstructorArgValue(accessExpression);
+			BeanMetadataElement matcher = createMatcher(matcherType, interceptMessage, parserContext);
+			matcherToExpression.put(matcher, authorizationManager.getBeanDefinition());
+		}
+		BeanDefinitionBuilder mds = BeanDefinitionBuilder
+				.rootBeanDefinition(RequestMatcherDelegatingAuthorizationManagerFactory.class);
+		mds.setFactoryMethod("createRequestMatcherDelegatingAuthorizationManager");
+		mds.addConstructorArgValue(matcherToExpression);
+		return context.registerWithGeneratedName(mds.getBeanDefinition());
+	}
+
+	private BeanMetadataElement createMatcher(MatcherType matcherType, Element urlElt, ParserContext parserContext) {
+		String path = urlElt.getAttribute(ATT_PATTERN);
+		String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF);
+		boolean hasMatcherRef = StringUtils.hasText(matcherRef);
+		if (!hasMatcherRef && !StringUtils.hasText(path)) {
+			parserContext.getReaderContext().error("path attribute cannot be empty or null", urlElt);
+		}
+		String method = urlElt.getAttribute(ATT_HTTP_METHOD);
+		if (!StringUtils.hasText(method)) {
+			method = null;
+		}
+		String servletPath = urlElt.getAttribute(ATT_SERVLET_PATH);
+		if (!StringUtils.hasText(servletPath)) {
+			servletPath = null;
+		}
+		else if (!MatcherType.mvc.equals(matcherType)) {
+			parserContext.getReaderContext().error(
+					ATT_SERVLET_PATH + " is not applicable for request-matcher: '" + matcherType.name() + "'", urlElt);
+		}
+		return hasMatcherRef ? new RuntimeBeanReference(matcherRef)
+				: matcherType.createMatcher(parserContext, path, method, servletPath);
+	}
+
+	String registerDefaultExpressionHandler(ParserContext pc) {
+		BeanDefinition expressionHandler = GrantedAuthorityDefaultsParserUtils.registerWithDefaultRolePrefix(pc,
+				DefaultWebSecurityExpressionHandlerBeanFactory.class);
+		String expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler);
+		pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
+		return expressionHandlerRef;
+	}
+
+	boolean isUseExpressions(Element elt) {
+		String useExpressions = elt.getAttribute(ATT_USE_EXPRESSIONS);
+		return !StringUtils.hasText(useExpressions) || "true".equals(useExpressions);
+	}
+
+	private static class RequestMatcherDelegatingAuthorizationManagerFactory {
+
+		private static AuthorizationManager<HttpServletRequest> createRequestMatcherDelegatingAuthorizationManager(
+				Map<RequestMatcher, AuthorizationManager<RequestAuthorizationContext>> beans) {
+			RequestMatcherDelegatingAuthorizationManager.Builder builder = RequestMatcherDelegatingAuthorizationManager
+					.builder();
+			for (Map.Entry<RequestMatcher, AuthorizationManager<RequestAuthorizationContext>> entry : beans
+					.entrySet()) {
+				builder.add(entry.getKey(), entry.getValue());
+			}
+			return builder.add(AnyRequestMatcher.INSTANCE, AuthenticatedAuthorizationManager.authenticated()).build();
+		}
+
+	}
+
+	static class DefaultWebSecurityExpressionHandlerBeanFactory
+			extends GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory {
+
+		private DefaultHttpSecurityExpressionHandler handler = new DefaultHttpSecurityExpressionHandler();
+
+		@Override
+		public DefaultHttpSecurityExpressionHandler getBean() {
+			this.handler.setDefaultRolePrefix(this.rolePrefix);
+			return this.handler;
+		}
+
+	}
+
+}

+ 35 - 1
config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java

@@ -41,6 +41,7 @@ import org.springframework.security.access.vote.RoleVoter;
 import org.springframework.security.config.Elements;
 import org.springframework.security.config.http.GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory;
 import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
 import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
 import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
 import org.springframework.security.web.access.channel.ChannelProcessingFilter;
@@ -113,6 +114,10 @@ class HttpConfigurationBuilder {
 
 	private static final String ATT_DISABLE_URL_REWRITING = "disable-url-rewriting";
 
+	private static final String ATT_USE_AUTHORIZATION_MGR = "use-authorization-manager";
+
+	private static final String ATT_AUTHORIZATION_MGR = "authorization-manager-ref";
+
 	private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
 
 	private static final String ATT_ONCE_PER_REQUEST = "once-per-request";
@@ -220,7 +225,7 @@ class HttpConfigurationBuilder {
 		createServletApiFilter(authenticationManager);
 		createJaasApiFilter();
 		createChannelProcessingFilter();
-		createFilterSecurityInterceptor(authenticationManager);
+		createFilterSecurity(authenticationManager);
 		createAddHeadersFilter();
 		createCorsFilter();
 		createWellKnownChangePasswordRedirectFilter();
@@ -675,6 +680,35 @@ class HttpConfigurationBuilder {
 		this.requestCacheAwareFilter.getConstructorArgumentValues().addGenericArgumentValue(this.requestCache);
 	}
 
+	private void createFilterSecurity(BeanReference authManager) {
+		boolean useAuthorizationManager = Boolean.parseBoolean(this.httpElt.getAttribute(ATT_USE_AUTHORIZATION_MGR));
+		if (useAuthorizationManager) {
+			createAuthorizationFilter();
+			return;
+		}
+		if (StringUtils.hasText(this.httpElt.getAttribute(ATT_AUTHORIZATION_MGR))) {
+			createAuthorizationFilter();
+			return;
+		}
+		createFilterSecurityInterceptor(authManager);
+	}
+
+	private void createAuthorizationFilter() {
+		AuthorizationFilterParser authorizationFilterParser = new AuthorizationFilterParser();
+		BeanDefinition fsiBean = authorizationFilterParser.parse(this.httpElt, this.pc);
+		String fsiId = this.pc.getReaderContext().generateBeanName(fsiBean);
+		this.pc.registerBeanComponent(new BeanComponentDefinition(fsiBean, fsiId));
+		// Create and register a AuthorizationManagerWebInvocationPrivilegeEvaluator for
+		// use with
+		// taglibs etc.
+		BeanDefinition wipe = BeanDefinitionBuilder
+				.rootBeanDefinition(AuthorizationManagerWebInvocationPrivilegeEvaluator.class)
+				.addConstructorArgReference(authorizationFilterParser.getAuthorizationManagerRef()).getBeanDefinition();
+		this.pc.registerBeanComponent(
+				new BeanComponentDefinition(wipe, this.pc.getReaderContext().generateBeanName(wipe)));
+		this.fsi = new RuntimeBeanReference(fsiId);
+	}
+
 	private void createFilterSecurityInterceptor(BeanReference authManager) {
 		boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(this.httpElt);
 		RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser

+ 6 - 0
config/src/main/resources/org/springframework/security/config/spring-security-5.8.rnc

@@ -350,6 +350,12 @@ http.attlist &=
 http.attlist &=
 	## If available, runs the request as the Subject acquired from the JaasAuthenticationToken. Defaults to "false".
 	attribute jaas-api-provision {xsd:boolean}?
+http.attlist &=
+	## Use AuthorizationManager API instead of SecurityMetadataSource
+	attribute use-authorization-manager {xsd:boolean}?
+http.attlist &=
+	## Use this AuthorizationManager instead of deriving one from <intercept-url> elements
+	attribute authorization-manager-ref {xsd:token}?
 http.attlist &=
 	## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.
 	attribute access-decision-manager-ref {xsd:token}?

+ 43 - 29
config/src/main/resources/org/springframework/security/config/spring-security-5.8.xsd

@@ -124,7 +124,7 @@
       </xs:annotation>
       <xs:complexType/>
    </xs:element>
-  
+
   <xs:attributeGroup name="password-encoder.attlist">
       <xs:attribute name="ref" type="xs:token">
          <xs:annotation>
@@ -408,7 +408,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="ldap-ap.attlist">
       <xs:attribute name="server-ref" type="xs:token">
          <xs:annotation>
@@ -488,7 +488,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="password-compare.attlist">
       <xs:attribute name="password-attribute" type="xs:token">
          <xs:annotation>
@@ -541,7 +541,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="protect.attlist">
       <xs:attribute name="method" use="required" type="xs:token">
          <xs:annotation>
@@ -842,13 +842,13 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
-  
-  
-  
-  
-  
-  
+
+
+
+
+
+
+
   <xs:attributeGroup name="protect-pointcut.attlist">
       <xs:attribute name="expression" use="required" type="xs:string">
          <xs:annotation>
@@ -1287,6 +1287,20 @@
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
+	  <xs:attribute name="use-authorization-manager" type="xs:boolean">
+		  <xs:annotation>
+			  <xs:documentation>Optional attribute specifying the ID of the AccessDecisionManager implementation which
+				  should be used for authorizing HTTP requests.
+			  </xs:documentation>
+		  </xs:annotation>
+	  </xs:attribute>
+	  <xs:attribute name="authorization-manager-ref" type="xs:token">
+		  <xs:annotation>
+			  <xs:documentation>Optional attribute specifying the ID of the AccessDecisionManager implementation which
+				  should be used for authorizing HTTP requests.
+			  </xs:documentation>
+		  </xs:annotation>
+	  </xs:attribute>
       <xs:attribute name="access-decision-manager-ref" type="xs:token">
          <xs:annotation>
             <xs:documentation>Optional attribute specifying the ID of the AccessDecisionManager implementation which
@@ -1335,7 +1349,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="access-denied-handler.attlist">
       <xs:attribute name="ref" type="xs:token">
          <xs:annotation>
@@ -1360,7 +1374,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="intercept-url.attlist">
       <xs:attribute name="pattern" type="xs:token">
          <xs:annotation>
@@ -1417,7 +1431,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="logout.attlist">
       <xs:attribute name="logout-url" type="xs:token">
          <xs:annotation>
@@ -1464,7 +1478,7 @@
          <xs:attributeGroup ref="security:ref"/>
       </xs:complexType>
    </xs:element>
-  
+
   <xs:attributeGroup name="form-login.attlist">
       <xs:attribute name="login-processing-url" type="xs:token">
          <xs:annotation>
@@ -1979,7 +1993,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:element name="attribute-exchange">
       <xs:annotation>
          <xs:documentation>Sets up an attribute exchange configuration to request specified attributes from the
@@ -2046,7 +2060,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="saml2-login.attlist">
       <xs:attribute name="relying-party-registration-repository-ref" type="xs:token">
          <xs:annotation>
@@ -2103,7 +2117,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="saml2-logout.attlist">
       <xs:attribute name="logout-url" type="xs:token">
          <xs:annotation>
@@ -2556,7 +2570,7 @@
          </xs:simpleType>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="http-basic.attlist">
       <xs:attribute name="entry-point-ref" type="xs:token">
          <xs:annotation>
@@ -2589,7 +2603,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="session-management.attlist">
       <xs:attribute name="session-fixation-protection">
          <xs:annotation>
@@ -2645,7 +2659,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="concurrency-control.attlist">
       <xs:attribute name="max-sessions" type="xs:token">
          <xs:annotation>
@@ -2692,7 +2706,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="remember-me.attlist">
       <xs:attribute name="key" type="xs:token">
          <xs:annotation>
@@ -2790,7 +2804,7 @@
   <xs:attributeGroup name="remember-me-data-source-ref">
       <xs:attributeGroup ref="security:data-source-ref"/>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="anonymous.attlist">
       <xs:attribute name="key" type="xs:token">
          <xs:annotation>
@@ -2823,8 +2837,8 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
-  
+
+
   <xs:attributeGroup name="http-port">
       <xs:attribute name="http" use="required" type="xs:token">
          <xs:annotation>
@@ -2841,7 +2855,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="x509.attlist">
       <xs:attribute name="subject-principal-regex" type="xs:token">
          <xs:annotation>
@@ -2978,7 +2992,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="ap.attlist">
       <xs:attribute name="ref" type="xs:token">
          <xs:annotation>
@@ -3030,7 +3044,7 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
-  
+
   <xs:attributeGroup name="user.attlist">
       <xs:attribute name="name" use="required" type="xs:token">
          <xs:annotation>
@@ -3773,4 +3787,4 @@
          <xs:enumeration value="LAST"/>
       </xs:restriction>
   </xs:simpleType>
-</xs:schema>
+</xs:schema>

+ 30 - 0
config/src/test/java/org/springframework/security/config/http/HttpConfigTests.java

@@ -16,6 +16,7 @@
 
 package org.springframework.security.config.http;
 
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponseWrapper;
 
@@ -26,12 +27,17 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.config.test.SpringTestContext;
 import org.springframework.security.config.test.SpringTestContextExtension;
 import org.springframework.security.web.FilterChainProxy;
 import org.springframework.test.web.servlet.MockMvc;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.verify;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -60,6 +66,30 @@ public class HttpConfigTests {
 		// @formatter:on
 	}
 
+	@Test
+	public void getWhenUsingMinimalAuthorizationManagerThenRedirectsToLogin() throws Exception {
+		this.spring.configLocations(this.xml("MinimalAuthorizationManager")).autowire();
+		// @formatter:off
+		this.mvc.perform(get("/"))
+				.andExpect(status().isFound())
+				.andExpect(redirectedUrl("http://localhost/login"));
+		// @formatter:on
+	}
+
+	@Test
+	public void getWhenUsingAuthorizationManagerThenRedirectsToLogin() throws Exception {
+		this.spring.configLocations(this.xml("AuthorizationManager")).autowire();
+		AuthorizationManager<HttpServletRequest> authorizationManager = this.spring.getContext()
+				.getBean(AuthorizationManager.class);
+		given(authorizationManager.check(any(), any())).willReturn(new AuthorizationDecision(false));
+		// @formatter:off
+		this.mvc.perform(get("/"))
+				.andExpect(status().isFound())
+				.andExpect(redirectedUrl("http://localhost/login"));
+		// @formatter:on
+		verify(authorizationManager).check(any(), any());
+	}
+
 	@Test
 	public void getWhenUsingMinimalConfigurationThenPreventsSessionAsUrlParameter() throws Exception {
 		this.spring.configLocations(this.xml("Minimal")).autowire();

+ 183 - 0
config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java

@@ -28,8 +28,10 @@ import org.mockito.stubbing.Answer;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
 import org.springframework.mock.web.MockServletContext;
+import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.config.test.SpringTestContext;
 import org.springframework.security.config.test.SpringTestContextExtension;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.request.RequestPostProcessor;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -37,6 +39,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.context.ConfigurableWebApplicationContext;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
@@ -75,6 +78,23 @@ public class InterceptUrlConfigTests {
 		// @formatter:on
 	}
 
+	/**
+	 * sec-2256
+	 */
+	@Test
+	public void requestWhenMethodIsSpecifiedAndAuthorizationManagerThenItIsNotGivenPriority() throws Exception {
+		this.spring.configLocations(this.xml("Sec2256AuthorizationManager")).autowire();
+		// @formatter:off
+		this.mvc.perform(post("/path").with(userCredentials()))
+				.andExpect(status().isOk());
+		this.mvc.perform(get("/path").with(userCredentials()))
+				.andExpect(status().isOk());
+		// @formatter:on
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	/**
 	 * sec-2355
 	 */
@@ -91,6 +111,25 @@ public class InterceptUrlConfigTests {
 		// @formatter:on
 	}
 
+	/**
+	 * sec-2355
+	 */
+	@Test
+	public void requestWhenUsingPatchAndAuthorizationManagerThenAuthorizesRequestsAccordingly() throws Exception {
+		this.spring.configLocations(this.xml("PatchMethodAuthorizationManager")).autowire();
+		// @formatter:off
+		this.mvc.perform(get("/path").with(userCredentials()))
+				.andExpect(status().isOk());
+		this.mvc.perform(patch("/path").with(userCredentials()))
+				.andExpect(status().isForbidden());
+		this.mvc.perform(patch("/path").with(adminCredentials()))
+				.andExpect(status().isOk());
+		// @formatter:on
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	@Test
 	public void requestWhenUsingHasAnyRoleThenAuthorizesRequestsAccordingly() throws Exception {
 		this.spring.configLocations(this.xml("HasAnyRole")).autowire();
@@ -102,6 +141,20 @@ public class InterceptUrlConfigTests {
 		// @formatter:on
 	}
 
+	@Test
+	public void requestWhenUsingHasAnyRoleAndAuthorizationManagerThenAuthorizesRequestsAccordingly() throws Exception {
+		this.spring.configLocations(this.xml("HasAnyRoleAuthorizationManager")).autowire();
+		// @formatter:off
+		this.mvc.perform(get("/path").with(userCredentials()))
+				.andExpect(status().isOk());
+		this.mvc.perform(get("/path").with(adminCredentials()))
+				.andExpect(status().isForbidden());
+		// @formatter:on
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	/**
 	 * sec-2059
 	 */
@@ -118,6 +171,26 @@ public class InterceptUrlConfigTests {
 		// @formatter:on
 	}
 
+	/**
+	 * sec-2059
+	 */
+	@Test
+	public void requestWhenUsingPathVariablesAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
+			throws Exception {
+		this.spring.configLocations(this.xml("PathVariablesAuthorizationManager")).autowire();
+		// @formatter:off
+		this.mvc.perform(get("/path/user/path").with(userCredentials()))
+				.andExpect(status().isOk());
+		this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
+				.andExpect(status().isForbidden());
+		this.mvc.perform(get("/path").with(userCredentials()))
+				.andExpect(status().isForbidden());
+		// @formatter:on
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	/**
 	 * gh-3786
 	 */
@@ -134,6 +207,26 @@ public class InterceptUrlConfigTests {
 		// @formatter:on
 	}
 
+	/**
+	 * gh-3786
+	 */
+	@Test
+	public void requestWhenUsingCamelCasePathVariablesAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
+			throws Exception {
+		this.spring.configLocations(this.xml("CamelCasePathVariablesAuthorizationManager")).autowire();
+		// @formatter:off
+		this.mvc.perform(get("/path/user/path").with(userCredentials()))
+				.andExpect(status().isOk());
+		this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
+				.andExpect(status().isForbidden());
+		this.mvc.perform(get("/PATH/user/path").with(userCredentials()))
+				.andExpect(status().isForbidden());
+		// @formatter:on
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	/**
 	 * sec-2059
 	 */
@@ -148,6 +241,24 @@ public class InterceptUrlConfigTests {
 		// @formatter:on
 	}
 
+	/**
+	 * sec-2059
+	 */
+	@Test
+	public void requestWhenUsingPathVariablesAndTypeConversionAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
+			throws Exception {
+		this.spring.configLocations(this.xml("TypeConversionPathVariablesAuthorizationManager")).autowire();
+		// @formatter:off
+		this.mvc.perform(get("/path/1/path").with(userCredentials()))
+				.andExpect(status().isOk());
+		this.mvc.perform(get("/path/2/path").with(userCredentials()))
+				.andExpect(status().isForbidden());
+		// @formatter:on
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	@Test
 	public void requestWhenUsingMvcMatchersThenAuthorizesRequestsAccordingly() throws Exception {
 		this.spring.configLocations(this.xml("MvcMatchers")).autowire();
@@ -156,6 +267,17 @@ public class InterceptUrlConfigTests {
 		this.mvc.perform(get("/path/")).andExpect(status().isUnauthorized());
 	}
 
+	@Test
+	public void requestWhenUsingMvcMatchersAndAuthorizationManagerThenAuthorizesRequestsAccordingly() throws Exception {
+		this.spring.configLocations(this.xml("MvcMatchersAuthorizationManager")).autowire();
+		this.mvc.perform(get("/path")).andExpect(status().isUnauthorized());
+		this.mvc.perform(get("/path.html")).andExpect(status().isUnauthorized());
+		this.mvc.perform(get("/path/")).andExpect(status().isUnauthorized());
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	@Test
 	public void requestWhenUsingMvcMatchersAndPathVariablesThenAuthorizesRequestsAccordingly() throws Exception {
 		this.spring.configLocations(this.xml("MvcMatchersPathVariables")).autowire();
@@ -169,6 +291,23 @@ public class InterceptUrlConfigTests {
 		// @formatter:on
 	}
 
+	@Test
+	public void requestWhenUsingMvcMatchersAndPathVariablesAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
+			throws Exception {
+		this.spring.configLocations(this.xml("MvcMatchersPathVariablesAuthorizationManager")).autowire();
+		// @formatter:off
+		this.mvc.perform(get("/path/user/path").with(userCredentials()))
+				.andExpect(status().isOk());
+		this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
+				.andExpect(status().isForbidden());
+		this.mvc.perform(get("/PATH/user/path").with(userCredentials()))
+				.andExpect(status().isForbidden());
+		// @formatter:on
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	@Test
 	public void requestWhenUsingMvcMatchersAndServletPathThenAuthorizesRequestsAccordingly() throws Exception {
 		this.spring.configLocations(this.xml("MvcMatchersServletPath")).autowire();
@@ -185,30 +324,74 @@ public class InterceptUrlConfigTests {
 		// @formatter:on
 	}
 
+	@Test
+	public void requestWhenUsingMvcMatchersAndServletPathAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
+			throws Exception {
+		this.spring.configLocations(this.xml("MvcMatchersServletPathAuthorizationManager")).autowire();
+		MockServletContext servletContext = mockServletContext("/spring");
+		ConfigurableWebApplicationContext context = this.spring.getContext();
+		context.setServletContext(servletContext);
+		// @formatter:off
+		this.mvc.perform(get("/spring/path").servletPath("/spring"))
+				.andExpect(status().isUnauthorized());
+		this.mvc.perform(get("/spring/path.html").servletPath("/spring"))
+				.andExpect(status().isUnauthorized());
+		this.mvc.perform(get("/spring/path/").servletPath("/spring"))
+				.andExpect(status().isUnauthorized());
+		// @formatter:on
+		assertThat(this.spring.getContext().getBeanNamesForType(FilterInvocationSecurityMetadataSource.class))
+				.isEmpty();
+		assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
+	}
+
 	@Test
 	public void configureWhenUsingAntMatcherAndServletPathThenThrowsException() {
 		assertThatExceptionOfType(BeanDefinitionParsingException.class)
 				.isThrownBy(() -> this.spring.configLocations(this.xml("AntMatcherServletPath")).autowire());
 	}
 
+	@Test
+	public void configureWhenUsingAntMatcherAndServletPathAndAuthorizationManagerThenThrowsException() {
+		assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(
+				() -> this.spring.configLocations(this.xml("AntMatcherServletPathAuthorizationManager")).autowire());
+	}
+
 	@Test
 	public void configureWhenUsingRegexMatcherAndServletPathThenThrowsException() {
 		assertThatExceptionOfType(BeanDefinitionParsingException.class)
 				.isThrownBy(() -> this.spring.configLocations(this.xml("RegexMatcherServletPath")).autowire());
 	}
 
+	@Test
+	public void configureWhenUsingRegexMatcherAndServletPathAndAuthorizationManagerThenThrowsException() {
+		assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(
+				() -> this.spring.configLocations(this.xml("RegexMatcherServletPathAuthorizationManager")).autowire());
+	}
+
 	@Test
 	public void configureWhenUsingCiRegexMatcherAndServletPathThenThrowsException() {
 		assertThatExceptionOfType(BeanDefinitionParsingException.class)
 				.isThrownBy(() -> this.spring.configLocations(this.xml("CiRegexMatcherServletPath")).autowire());
 	}
 
+	@Test
+	public void configureWhenUsingCiRegexMatcherAndServletPathAndAuthorizationManagerThenThrowsException() {
+		assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(() -> this.spring
+				.configLocations(this.xml("CiRegexMatcherServletPathAuthorizationManager")).autowire());
+	}
+
 	@Test
 	public void configureWhenUsingDefaultMatcherAndServletPathThenThrowsException() {
 		assertThatExceptionOfType(BeanDefinitionParsingException.class)
 				.isThrownBy(() -> this.spring.configLocations(this.xml("DefaultMatcherServletPath")).autowire());
 	}
 
+	@Test
+	public void configureWhenUsingDefaultMatcherAndServletPathAndAuthorizationManagerThenThrowsException() {
+		assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(() -> this.spring
+				.configLocations(this.xml("DefaultMatcherServletPathAuthorizationManager")).autowire());
+	}
+
 	private static RequestPostProcessor adminCredentials() {
 		return httpBasic("admin", "password");
 	}

+ 36 - 0
config/src/test/resources/org/springframework/security/config/http/HttpConfigTests-AuthorizationManager.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http auto-config="true" authorization-manager-ref="ref">
+		<intercept-url pattern="/**" access="permitAll"/>
+	</http>
+
+	<b:bean id="ref" class="org.mockito.Mockito" factory-method="mock">
+		<b:constructor-arg value="org.springframework.security.authorization.AuthorizationManager"/>
+	</b:bean>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 32 - 0
config/src/test/resources/org/springframework/security/config/http/HttpConfigTests-MinimalAuthorizationManager.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http auto-config="true" use-authorization-manager="true">
+		<intercept-url pattern="/**" access="hasRole('USER')"/>
+	</http>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 33 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-AntMatcherServletPathAuthorizationManager.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http request-matcher="ant" use-authorization-manager="true">
+		<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
+		<http-basic/>
+	</http>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 36 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariablesAuthorizationManager.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http auto-config="true" use-authorization-manager="true">
+		<intercept-url pattern="/path/{userName}/**" access="#userName == authentication.name"/>
+		<intercept-url pattern="/**" access="denyAll"/>
+		<http-basic/>
+	</http>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 33 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CiRegexMatcherServletPathAuthorizationManager.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http request-matcher="ciRegex" use-authorization-manager="true">
+		<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
+		<http-basic/>
+	</http>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 33 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPathAuthorizationManager.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http use-authorization-manager="true">
+		<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
+		<http-basic/>
+	</http>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 35 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-HasAnyRoleAuthorizationManager.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http auto-config="true" use-authorization-manager="true">
+		<intercept-url pattern="/**" access="hasAnyRole('ROLE_DEVELOPER', 'ROLE_USER')"/>
+		<http-basic/>
+	</http>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 42 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersAuthorizationManager.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:mvc="http://www.springframework.org/schema/mvc"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd
+			http://www.springframework.org/schema/mvc
+			https://www.springframework.org/schema/mvc/spring-mvc.xsd">
+
+	<http auto-config="true" request-matcher="mvc" use-authorization-manager="true">
+		<intercept-url pattern="/path" access="denyAll"/>
+		<http-basic/>
+	</http>
+
+	<mvc:annotation-driven>
+		<mvc:path-matching suffix-pattern="true"/>
+	</mvc:annotation-driven>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 41 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersPathVariablesAuthorizationManager.xml

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		 xmlns:mvc="http://www.springframework.org/schema/mvc"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd
+			http://www.springframework.org/schema/mvc
+			https://www.springframework.org/schema/mvc/spring-mvc.xsd">
+
+	<http auto-config="true" use-authorization-manager="true">
+		<intercept-url pattern="/path/{un}/**" access="#un == 'user'"/>
+		<intercept-url pattern="/**" access="denyAll"/>
+		<http-basic/>
+	</http>
+
+	<mvc:annotation-driven/>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 42 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPathAuthorizationManager.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:mvc="http://www.springframework.org/schema/mvc"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd
+			http://www.springframework.org/schema/mvc
+			https://www.springframework.org/schema/mvc/spring-mvc.xsd">
+
+	<http auto-config="true" request-matcher="mvc" use-authorization-manager="true">
+		<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
+		<http-basic/>
+	</http>
+
+	<mvc:annotation-driven>
+		<mvc:path-matching suffix-pattern="true"/>
+	</mvc:annotation-driven>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 36 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethodAuthorizationManager.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http auto-config="true" use-authorization-manager="true">
+		<intercept-url pattern="/**" method="PATCH" access="hasRole('ADMIN')"/>
+		<http-basic/>
+		<csrf disabled="true"/>
+	</http>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 36 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariablesAuthorizationManager.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http auto-config="true" use-authorization-manager="true">
+		<intercept-url pattern="/path/{un}/**" access="#un == authentication.name"/>
+		<intercept-url pattern="/**" access="denyAll"/>
+		<http-basic/>
+	</http>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 33 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-RegexMatcherServletPathAuthorizationManager.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http request-matcher="regex" use-authorization-manager="true">
+		<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
+		<http-basic/>
+	</http>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 37 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256AuthorizationManager.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http auto-config="true" use-authorization-manager="true">
+		<intercept-url pattern="/path" access="hasRole('USER')"/>
+		<intercept-url pattern="/path" method="GET" access="denyAll"/>
+		<http-basic/>
+		<csrf disabled="true"/>
+	</http>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 37 - 0
config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariablesAuthorizationManager.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2002-2018 the original author or authors.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~       https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xmlns="http://www.springframework.org/schema/security"
+		xsi:schemaLocation="
+			http://www.springframework.org/schema/security
+			https://www.springframework.org/schema/security/spring-security.xsd
+			http://www.springframework.org/schema/beans
+			https://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<http auto-config="true" use-authorization-manager="true">
+		<intercept-url pattern="/path/{un}/**" access="@id.isOne(#un)"/>
+		<intercept-url pattern="/**" access="denyAll"/>
+		<http-basic/>
+	</http>
+
+	<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
+	<b:bean name="id" class="org.springframework.security.config.http.InterceptUrlConfigTests.Id"/>
+
+	<b:import resource="userservice.xml"/>
+</b:beans>

+ 7 - 0
docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc

@@ -29,6 +29,13 @@ These are fixed and cannot be replaced with alternatives.
 === <http> Attributes
 The attributes on the `<http>` element control some of the properties on the core filters.
 
+[[nsa-http-use-authorization-manager]]
+* **use-authorization-manager**
+Use AuthorizationManager API instead of SecurityMetadataSource
+
+[[nsa-http-authorization-manager-ref]]
+* **access-decision-manager-ref**
+Use this AuthorizationManager instead of deriving one from <intercept-url> elements
 
 [[nsa-http-access-decision-manager-ref]]
 * **access-decision-manager-ref**