Browse Source

Revisit Request and Method Security Docs

Issue gh-13088
Josh Cummings 2 years ago
parent
commit
e5fcf1ebcf

BIN
docs/modules/ROOT/assets/images/servlet/authorization/methodsecurity.odg


BIN
docs/modules/ROOT/assets/images/servlet/authorization/methodsecurity.png


+ 0 - 2
docs/modules/ROOT/nav.adoc

@@ -59,9 +59,7 @@
 ** xref:servlet/authorization/index.adoc[Authorization]
 *** xref:servlet/authorization/architecture.adoc[Authorization Architecture]
 *** xref:servlet/authorization/authorize-http-requests.adoc[Authorize HTTP Requests]
-*** xref:servlet/authorization/authorize-requests.adoc[Authorize HTTP Requests with FilterSecurityInterceptor]
 *** xref:servlet/authorization/expression-based.adoc[Expression-Based Access Control]
-*** xref:servlet/authorization/secure-objects.adoc[Secure Object Implementations]
 *** xref:servlet/authorization/method-security.adoc[Method Security]
 *** xref:servlet/authorization/acls.adoc[Domain Object Security ACLs]
 *** xref:servlet/authorization/events.adoc[Authorization Events]

+ 1 - 1
docs/modules/ROOT/pages/migration/servlet/authorization.adoc

@@ -36,7 +36,7 @@ There are no further migrations steps for Java or Kotlin for this feature.
 == Use `AuthorizationManager` for Request Security
 
 In 6.0, `<http>` defaults `once-per-request` to `false`, `filter-all-dispatcher-types` to `true`, and `use-authorization-manager` to `true`.
-Also, xref:servlet/authorization/authorize-requests.adoc#filtersecurityinterceptor-every-request[`authorizeRequests#filterSecurityInterceptorOncePerRequest`] defaults to `false` and xref:servlet/authorization/authorize-http-requests.adoc[`authorizeHttpRequests#filterAllDispatcherTypes`] defaults to `true`.
+Also, {security-api-url}org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.AbstractInterceptUrlRegistry.html#filterSecurityInterceptorOncePerRequest(boolean)[`authorizeRequests#filterSecurityInterceptorOncePerRequest`] defaults to `false` and xref:servlet/authorization/authorize-http-requests.adoc[`authorizeHttpRequests#filterAllDispatcherTypes`] defaults to `true`.
 So, to complete migration, any defaults values can be removed.
 
 For example, if you opted in to the 6.0 default for `filter-all-dispatcher-types` or `authorizeHttpRequests#filterAllDispatcherTypes` like so:

+ 1 - 1
docs/modules/ROOT/pages/servlet/architecture.adoc

@@ -194,7 +194,7 @@ The following is a comprehensive list of Spring Security Filter ordering:
 * `OAuth2AuthorizationCodeGrantFilter`
 * `SessionManagementFilter`
 * <<servlet-exceptiontranslationfilter,`ExceptionTranslationFilter`>>
-* xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`]
+* xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`]
 * `SwitchUserFilter`
 
 [[servlet-exceptiontranslationfilter]]

+ 1 - 1
docs/modules/ROOT/pages/servlet/authentication/passwords/basic.adoc

@@ -15,7 +15,7 @@ The preceding figure builds off our xref:servlet/architecture.adoc#servlet-secur
 
 image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource `/private` for which it is not authorized.
 
-image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
+image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
 
 image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates __Start Authentication__.
 The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`], which sends a WWW-Authenticate header.

+ 1 - 1
docs/modules/ROOT/pages/servlet/authentication/passwords/form.adoc

@@ -16,7 +16,7 @@ The preceding figure builds off our xref:servlet/architecture.adoc#servlet-secur
 
 image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource (`/private`) for which it is not authorized.
 
-image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
+image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
 
 image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates __Start Authentication__ and sends a redirect to the login page with the configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`].
 In most cases, the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`].

+ 59 - 9
docs/modules/ROOT/pages/servlet/authorization/architecture.adoc

@@ -23,30 +23,76 @@ String getAuthority();
 ----
 ====
 
-This method lets an
-`AccessDecisionManager` instance to obtain a precise `String` representation of the `GrantedAuthority`.
-By returning a representation as a `String`, a `GrantedAuthority` can be easily "`read`" by most `AccessDecisionManager` implementations.
-If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "`complex`" and `getAuthority()` must return `null`.
+This method is used by an
+`AuthorizationManager` instance to obtain a precise `String` representation of the `GrantedAuthority`.
+By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most `AuthorizationManager` implementations.
+If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "complex" and `getAuthority()` must return `null`.
 
-An example of a "`complex`" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers.
+An example of a complex `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers.
 Representing this complex `GrantedAuthority` as a `String` would be quite difficult. As a result, the `getAuthority()` method should return `null`.
-This indicates to any `AccessDecisionManager` that it needs to support the specific `GrantedAuthority` implementation to understand its contents.
+This indicates to any `AuthorizationManager` that it needs to support the specific `GrantedAuthority` implementation to understand its contents.
 
 Spring Security includes one concrete `GrantedAuthority` implementation: `SimpleGrantedAuthority`.
 This implementation lets any user-specified `String` be converted into a `GrantedAuthority`.
 All `AuthenticationProvider` instances included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object.
 
+[[jc-method-security-custom-granted-authority-defaults]]
+By default, role-based authorization rules include `ROLE_` as a prefix.
+This means that if there is an authorization rule that requires a security context to have a role of "USER", Spring Security will by default look for a `GrantedAuthority#getAuthority` that returns "ROLE_USER".
+
+You can customize this with `GrantedAuthorityDefaults`.
+`GrantedAuthorityDefaults` exists to allow customizing the prefix to use for role-based authorization rules.
+
+You can configure the authorization rules to use a different prefix by exposing a `GrantedAuthorityDefaults` bean, like so:
+
+.Custom MethodSecurityExpressionHandler
+====
+.Java
+[source,java,role="primary"]
+----
+@Bean
+static GrantedAuthorityDefaults grantedAuthorityDefaults() {
+	return new GrantedAuthorityDefaults("MYPREFIX_");
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+companion object {
+	@Bean
+	fun grantedAuthorityDefaults() : GrantedAuthorityDefaults {
+		return GrantedAuthorityDefaults("MYPREFIX_");
+	}
+}
+----
+
+.Xml
+[source,xml,role="secondary"]
+----
+<bean id="grantedAuthorityDefaults" class="org.springframework.security.config.core.GrantedAuthorityDefaults">
+	<constructor-arg value="MYPREFIX_"/>
+</bean>
+----
+====
+
+[TIP]
+====
+You expose `GrantedAuthorityDefaults` using a `static` method to ensure that Spring publishes it before it initializes Spring Security's method security `@Configuration` classes
+====
+
 [[authz-pre-invocation]]
-== Pre-Invocation Handling
+== Invocation Handling
 Spring Security provides interceptors that control access to secure objects, such as method invocations or web requests.
-A pre-invocation decision on whether the invocation is allowed to proceed is made by the `AccessDecisionManager`.
+A pre-invocation decision on whether the invocation is allowed to proceed is made by `AuthorizationManager` instances.
+Also post-invocation decisions on whether a given value may be returned is made by `AuthorizationManager` instances.
 
 === The AuthorizationManager
 `AuthorizationManager` supersedes both <<authz-legacy-note,`AccessDecisionManager` and `AccessDecisionVoter`>>.
 
 Applications that customize an `AccessDecisionManager` or `AccessDecisionVoter` are encouraged to <<authz-voter-adaptation,change to using `AuthorizationManager`>>.
 
-``AuthorizationManager``s are called by the xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] and are responsible for making final access control decisions.
+``AuthorizationManager``s are called by Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[request-based], xref:servlet/authorization/method-security.adoc[method-based], and xref:servlet/integrations/websocket.adoc[message-based] authorization components and are responsible for making final access control decisions.
 The `AuthorizationManager` interface contains two methods:
 
 ====
@@ -97,6 +143,10 @@ Another manager is the `AuthenticatedAuthorizationManager`.
 It can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users.
 Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access.
 
+[[authz-authorization-managers]]
+==== AuthorizationManagers
+There are also helpful static factories in `AuthenticationManagers` for composing individual ``AuthenticationManager``s into more sophisticated expressions.
+
 [[authz-custom-authorization-manager]]
 ==== Custom Authorization Managers
 Obviously, you can also implement a custom `AuthorizationManager` and you can put just about any access-control logic you want in it.

+ 696 - 199
docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc

@@ -1,61 +1,172 @@
 [[servlet-authorization-authorizationfilter]]
-= Authorize HttpServletRequests with AuthorizationFilter
+= Authorize HttpServletRequests
 :figures: servlet/authorization
 
-This section builds on xref:servlet/architecture.adoc#servlet-architecture[Servlet Architecture and Implementation] by digging deeper into how xref:servlet/authorization/index.adoc#servlet-authorization[authorization] works within Servlet-based applications.
+Spring Security allows you to xref:servlet/authorization/index.adoc[model your authorization] at the request level.
+For example, with Spring Security you can say that all pages under `/admin` require one authority while all other pages simply require authentication.
 
-[NOTE]
-`AuthorizationFilter` supersedes xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`].
-To remain backward compatible, `FilterSecurityInterceptor` remains the default.
-This section discusses how `AuthorizationFilter` works and how to override the default configuration.
+By default, Spring Security requires that every request be authenticated.
+That said, any time you use xref:servlet/configuration/java.adoc#jc-httpsecurity[an `HttpSecurity` instance], it's necessary to declare your authorization rules.
 
-The {security-api-url}org/springframework/security/web/access/intercept/AuthorizationFilter.html[`AuthorizationFilter`] provides xref:servlet/authorization/index.adoc#servlet-authorization[authorization] for ``HttpServletRequest``s.
-It is inserted into the xref:servlet/architecture.adoc#servlet-filterchainproxy[FilterChainProxy] as one of the xref:servlet/architecture.adoc#servlet-security-filters[Security Filters].
-
-You can override the default when you declare a `SecurityFilterChain`.
-Instead of using xref:servlet/authorization/authorize-http-requests.adoc#servlet-authorize-requests-defaults[`authorizeRequests`], use `authorizeHttpRequests`, like so:
+[[activate-request-security]]
+Whenever you have an `HttpSecurity` instance, you should at least do:
 
 .Use authorizeHttpRequests
 ====
 .Java
 [source,java,role="primary"]
 ----
-@Bean
-SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .anyRequest().authenticated();
-        )
-        // ...
+http
+    .authorizeHttpRequests((authorize) -> authorize
+        .anyRequest().authenticated()
+    )
+----
 
-    return http.build();
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+http {
+    authorizeHttpRequests {
+        authorize(anyRequest, authenticated)
+    }
 }
 ----
+
+.Xml
+[source,xml,role="secondary"]
+----
+<http>
+    <intercept-url pattern="/**" access="authenticated"/>
+</http>
+----
 ====
 
-This improves on `authorizeRequests` in a number of ways:
+This tells Spring Security that any endpoint in your application requires that the security context at a minimum be authenticated in order to allow it.
 
-1. Uses the simplified `AuthorizationManager` API instead of metadata sources, config attributes, decision managers, and voters.
-This simplifies reuse and customization.
-2. Delays `Authentication` lookup.
-Instead of the authentication needing to be looked up for every request, it will only look it up in requests where an authorization decision requires authentication.
-3. Bean-based configuration support.
+In many cases, your authorization rules will be more sophisticated than that, so please consider the following use cases:
+
+* I have an app that uses `authorizeRequests` and I want to <<migrate-authorize-requests,migrate it to `authorizeHttpRequests`>>
+* I want to <<request-authorization-architecture,understand how the `AuthorizationFilter` components work>>
+* I want to <<match-requests, match requests>> based on a pattern; specifically <<match-by-regex,regex>>
+* I want to <<authorize-requests, authorize requests>>
+* I want to <<match-by-custom, match a request programmatically>>
+* I want to <<authorize-requests, authorize a request programmatically>>
+* I want to <<remote-authorization-manager, delegate request authorization>> to a policy agent
 
-When `authorizeHttpRequests` is used instead of `authorizeRequests`, then {security-api-url}org/springframework/security/web/access/intercept/AuthorizationFilter.html[`AuthorizationFilter`] is used instead of xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`].
+[[request-authorization-architecture]]
+== Understanding How Request Authorization Components Work
+
+[NOTE]
+This section builds on xref:servlet/architecture.adoc#servlet-architecture[Servlet Architecture and Implementation] by digging deeper into how xref:servlet/authorization/index.adoc#servlet-authorization[authorization] works at the request level in Servlet-based applications.
 
 .Authorize HttpServletRequest
 image::{figures}/authorizationfilter.png[]
 
-* image:{icondir}/number_1.png[] First, the `AuthorizationFilter` obtains an  xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
-It wraps this in an `Supplier` in order to delay lookup.
+* image:{icondir}/number_1.png[] First, the `AuthorizationFilter` constructs a `Supplier` that retrieves an  xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
 * image:{icondir}/number_2.png[] Second, it passes the `Supplier<Authentication>` and the `HttpServletRequest` to the xref:servlet/architecture.adoc#authz-authorization-manager[`AuthorizationManager`].
-** image:{icondir}/number_3.png[] If authorization is denied, an `AccessDeniedException` is thrown.
+The `AuthorizationManager` matches the request to the patterns in `authorizeHttpRequests`, and runs the corresponding rule.
+** image:{icondir}/number_3.png[] If authorization is denied, xref:servlet/authorization/events.adoc[an `AuthorizationDeniedEvent` is published], and an `AccessDeniedException` is thrown.
 In this case the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] handles the `AccessDeniedException`.
-** image:{icondir}/number_4.png[] If access is granted, `AuthorizationFilter` continues with the xref:servlet/architecture.adoc#servlet-filters-review[FilterChain] which allows the application to process normally.
+** image:{icondir}/number_4.png[] If access is granted, xref:servlet/authorization/events.adoc[an `AuthorizationGrantedEvent` is published] and `AuthorizationFilter` continues with the xref:servlet/architecture.adoc#servlet-filters-review[FilterChain] which allows the application to process normally.
 
-We can configure Spring Security to have different rules by adding more rules in order of precedence.
+=== `AuthorizationFilter` Is Last By Default
 
-.Authorize Requests
+The `AuthorizationFilter` is last in xref:servlet/architecture.adoc#servlet-filterchain-figure[the Spring Security filter chain] by default.
+This means that Spring Security's xref:servlet/authentication/index.adoc[authentication filters], xref:servlet/exploits/index.adoc[exploit protections], and other filter integrations do not require authorization.
+If you add filters of your own before the `AuthorizationFilter`, they will also not require authorization; otherwise, they will.
+
+A place where this typically becomes important is when you are adding {spring-framework-reference-url}web.html#spring-web[Spring MVC] endpoints.
+Because they are executed by the {spring-framework-reference-url}web.html#mvc-servlet[`DispatcherServlet`] and this comes after the `AuthorizationFilter`, you're endpoints need to be <<authorizing-endpoints,included in `authorizeHttpRequests` to be permitted>>.
+
+=== All Dispatches Are Authorized
+
+The `AuthorizationFilter` runs not just on every request, but on every dispatch.
+This means that the `REQUEST` dispatch needs authorization, but also ``FORWARD``s, ``ERROR``s, and ``INCLUDE``s.
+
+For example, {spring-framework-reference-url}web.html#spring-web[Spring MVC] can `FORWARD` the request to a view resolver that renders a Thymeleaf template, like so:
+
+.Sample Forwarding Spring MVC Controller
+====
+.Java
+[source,java,role="primary"]
+----
+@Controller
+public class MyController {
+    @GetMapping("/endpoint")
+    public String endpoint() {
+        return "endpoint";
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@Controller
+class MyController {
+    @GetMapping("/endpoint")
+    fun endpoint(): String {
+        return "endpoint"
+    }
+}
+----
+====
+
+In this case, authorization happens twice; once for authorizing `/endpoint` and once for forwarding to Thymeleaf to render the "endpoint" template.
+
+For that reason, you may want to <<match-by-dispatcher-type, permit all `FORWARD` dispatches>>.
+
+Another example of this principle is {spring-boot-reference-url}web.html#web.servlet.spring-mvc.error-handling[how Spring Boot handles errors].
+If the container catches an exception, say like the following:
+
+.Sample Erroring Spring MVC Controller
+====
+.Java
+[source,java,role="primary"]
+----
+@Controller
+public class MyController {
+    @GetMapping("/endpoint")
+    public String endpoint() {
+        throw new UnsupportedOperationException("unsupported");
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@Controller
+class MyController {
+    @GetMapping("/endpoint")
+    fun endpoint(): String {
+        throw UnsupportedOperationException("unsupported")
+    }
+}
+----
+====
+
+then Boot will dispatch it to the `ERROR` dispatch.
+
+In that case, authorization also happens twice; once for authorizing `/endpoint` and once for dispatching the error.
+
+For that reason, you may want to <<match-by-dispatcher-type, permit all `ERROR` dispatches>>.
+
+=== `Authentication` Lookup is Deferred
+
+Remember that xref:servlet/authorization/architecture.adoc#_the_authorizationmanager[the `AuthorizationManager` API uses a `Supplier<Authentication>`].
+
+This matters with `authorizeHttpRequests` when requests are <<authorize-requests,always permitted or always denied>>.
+In those cases, xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[the `Authentication`] is not queried, making for a faster request.
+
+[[authorizing-endpoints]]
+== Authorizing an Endpoint
+
+You can configure Spring Security to have different rules by adding more rules in order of precedence.
+
+If you want to require that `/endpoint` only be accessible by end users with the `USER` authority, then you can do:
+
+.Authorize an Endpoint
 ====
 .Java
 [source,java,role="primary"]
@@ -63,225 +174,649 @@ We can configure Spring Security to have different rules by adding more rules in
 @Bean
 SecurityFilterChain web(HttpSecurity http) throws Exception {
 	http
-		// ...
-		.authorizeHttpRequests(authorize -> authorize                                  // <1>
-			.requestMatchers("/resources/**", "/signup", "/about").permitAll()         // <2>
-			.requestMatchers("/admin/**").hasRole("ADMIN")                             // <3>
-			.requestMatchers("/db/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') and hasRole('DBA')"))   // <4>
-			// .requestMatchers("/db/**").access(AuthorizationManagers.allOf(AuthorityAuthorizationManager.hasRole("ADMIN"), AuthorityAuthorizationManager.hasRole("DBA")))   // <5>
-			.anyRequest().denyAll()                                                // <6>
-		);
+		.authorizeHttpRequests((authorize) -> authorize
+			.requestMatchers("/endpoint").hasAuthority('USER')
+			.anyRequest().authenticated()
+		)
+        // ...
 
 	return http.build();
 }
 ----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@Bean
+SecurityFilterChain web(HttpSecurity http) throws Exception {
+	http {
+        authorizeHttpRequests {
+            authorize("/endpoint", hasAuthority('USER'))
+            authorize(anyRequest, authenticated)
+        }
+	}
+	return http.build();
+}
+----
+
+.Xml
+[source,xml,role="secondary"]
+----
+<http>
+    <intercept-url pattern="/endpoint" access="hasAuthority('USER')"/>
+    <intercept-url pattern="/**" access="authenticated"/>
+</http>
+----
 ====
-<1> There are multiple authorization rules specified.
-Each rule is considered in the order they were declared.
-<2> We specified multiple URL patterns that any user can access.
-Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about".
-<3> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN".
-You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix.
-<4> Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA".
-You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
-<5> The same rule from 4, could be written by combining multiple `AuthorizationManager`.
-<6> Any URL that has not already been matched on is denied access.
-This is a good strategy if you do not want to accidentally forget to update your authorization rules.
 
-You can take a bean-based approach by constructing your own xref:servlet/authorization/architecture.adoc#authz-delegate-authorization-manager[`RequestMatcherDelegatingAuthorizationManager`] like so:
+As you can see, the declaration can be broken up in to pattern/rule pairs.
+
+`AuthorizationFilter` processes these pairs in the order listed, applying only the first match to the request.
+This means that even though `/**` would also match for `/endpoint` the above rules are not a problem.
+The way to read the above rules is "if the request is `/endpoint`, then require the `USER` authority; else, only require authentication".
+
+Spring Security supports several patterns and several rules; you can also programmatically create your own of each.
+
+Once authorized, you can test it using xref:servlet/test/method.adoc#test-method-withmockuser[Security's test support] in the following way:
 
-.Configure RequestMatcherDelegatingAuthorizationManager
+.Test Endpoint Authorization
 ====
 .Java
 [source,java,role="primary"]
 ----
-@Bean
-SecurityFilterChain web(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> access)
-        throws AuthenticationException {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .anyRequest().access(access)
-        )
-        // ...
+@WithMockUser(authorities="USER")
+@Test
+void endpointWhenUserAuthorityThenAuthorized() {
+    this.mvc.perform(get("/endpoint"))
+        .andExpect(status().isOk());
+}
 
-    return http.build();
+@WithMockUser
+@Test
+void endpointWhenNotUserAuthorityThenForbidden() {
+    this.mvc.perform(get("/endpoint"))
+        .andExpect(status().isForbidden());
 }
 
-@Bean
-AuthorizationManager<RequestAuthorizationContext> requestMatcherAuthorizationManager(HandlerMappingIntrospector introspector) {
-    MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
-    RequestMatcher permitAll =
-            new AndRequestMatcher(
-                    mvcMatcherBuilder.pattern("/resources/**"),
-                    mvcMatcherBuilder.pattern("/signup"),
-                    mvcMatcherBuilder.pattern("/about"));
-    RequestMatcher admin = mvcMatcherBuilder.pattern("/admin/**");
-    RequestMatcher db = mvcMatcherBuilder.pattern("/db/**");
-    RequestMatcher any = AnyRequestMatcher.INSTANCE;
-    AuthorizationManager<HttpServletRequest> manager = RequestMatcherDelegatingAuthorizationManager.builder()
-            .add(permitAll, (context) -> new AuthorizationDecision(true))
-            .add(admin, AuthorityAuthorizationManager.hasRole("ADMIN"))
-            .add(db, AuthorityAuthorizationManager.hasRole("DBA"))
-            .add(any, new AuthenticatedAuthorizationManager())
-            .build();
-    return (context) -> manager.check(context.getRequest());
+@Test
+void anyWhenUnauthenticatedThenUnauthorized() {
+    this.mvc.perform(get("/any"))
+        .andExpect(status().isUnauthorized())
 }
 ----
 ====
 
-You can also wire xref:servlet/authorization/architecture.adoc#authz-custom-authorization-manager[your own custom authorization managers] for any request matcher.
+[[match-requests]]
+== Matching Requests
+
+Above you've already seen <<authorizing-endpoints, two ways to match requests>>.
+
+The first you saw was the simplest, which is to match any request.
 
-Here is an example of mapping a custom authorization manager to the `my/authorized/endpoint`:
+The second is to match by a URI pattern.
+Spring Security supports two languages for URI pattern-matching: <<match-by-ant,Ant>> (as seen above) and <<match-by-regex,Regular Expressions>>.
 
-.Custom Authorization Manager
+[[match-by-ant]]
+=== Matching Using Ant
+Ant is the default language that Spring Security uses to match requests.
+
+You can use it to match a single endpoint or a directory, and you can even capture placeholders for later use.
+You can also refine it to match a specific set of HTTP methods.
+
+Let's say that you instead of wanting to match the `/endpoint` endpoint, you want to match all endpoints under the `/resource` directory.
+In that case, you can do something like the following:
+
+.Match with Ant
 ====
 .Java
 [source,java,role="primary"]
 ----
-@Bean
-SecurityFilterChain web(HttpSecurity http) throws Exception {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .requestMatchers("/my/authorized/endpoint").access(new CustomAuthorizationManager());
-        )
-        // ...
+http
+    .authorizeHttpRequests((authorize) -> authorize
+        .requestMatchers("/resource/**").hasAuthority("USER")
+        .anyRequest().authenticated()
+    )
+----
 
-    return http.build();
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+http {
+    authorizeHttpRequests {
+        authorize("/resource/**", hasAuthority("USER"))
+        authorize(anyRequest, authenticated)
+    }
 }
 ----
+
+.Xml
+[source,xml,role="secondary"]
+----
+<http>
+    <intercept-url pattern="/resource/**" access="hasAuthority('USER')"/>
+    <intercept-url pattern="/**" access="authenticated"/>
+</http>
+----
 ====
 
-Or you can provide it for all requests as seen below:
+The way to read this is "if the request is `/resource` or some subdirectory, require the `USER` authority; otherwise, only require authentication"
 
-.Custom Authorization Manager for All Requests
+You can also extract path values from the request, as seen below:
+
+.Authorize and Extract
 ====
 .Java
 [source,java,role="primary"]
 ----
-@Bean
-SecurityFilterChain web(HttpSecurity http) throws Exception {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .anyRequest().access(new CustomAuthorizationManager());
-        )
-        // ...
+http
+    .authorizeHttpRequests((authorize) -> authorize
+        .requestMatchers("/resource/{name}").access(new WebExpressionAuthorizationManager("#name == authentication.name"))
+        .anyRequest().authenticated()
+    )
+----
 
-    return http.build();
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+http {
+    authorizeHttpRequests {
+        authorize("/resource/{name}", WebExpressionAuthorizationManager("#name == authentication.name"))
+        authorize(anyRequest, authenticated)
+    }
 }
 ----
+
+.Xml
+[source,xml,role="secondary"]
+----
+<http>
+    <intercept-url pattern="/resource/{name}" access="#name == authentication.name"/>
+    <intercept-url pattern="/**" access="authenticated"/>
+</http>
+----
 ====
 
-By default, the `AuthorizationFilter` applies to all dispatcher types.
-We can configure Spring Security to not apply the authorization rules to all dispatcher types by using the `shouldFilterAllDispatcherTypes` method:
+Once authorized, you can test it using xref:servlet/test/method.adoc#test-method-withmockuser[Security's test support] in the following way:
 
-.Set shouldFilterAllDispatcherTypes to false
+.Test Directory Authorization
 ====
 .Java
 [source,java,role="primary"]
 ----
-@Bean
-SecurityFilterChain web(HttpSecurity http) throws Exception {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .shouldFilterAllDispatcherTypes(false)
-            .anyRequest().authenticated()
-        )
-        // ...
+@WithMockUser(authorities="USER")
+@Test
+void endpointWhenUserAuthorityThenAuthorized() {
+    this.mvc.perform(get("/endpoint/jon"))
+        .andExpect(status().isOk());
+}
 
-    return http.build();
+@WithMockUser
+@Test
+void endpointWhenNotUserAuthorityThenForbidden() {
+    this.mvc.perform(get("/endpoint/jon"))
+        .andExpect(status().isForbidden());
+}
+
+@Test
+void anyWhenUnauthenticatedThenUnauthorized() {
+    this.mvc.perform(get("/any"))
+        .andExpect(status().isUnauthorized())
 }
 ----
+====
+
+[NOTE]
+Spring Security only matches paths.
+If you want to match query parameters, you will need a custom request matcher.
+
+[[match-by-regex]]
+=== Matching Using Regular Expressions
+Spring Security supports matching requests against a regular expression.
+This can come in handy if you want to apply more strict matching criteria than `**` on a subdirectory.
+
+For example, consider a path that contains the username and the rule that all usernames must be alphanumeric.
+You can use {security-api-url}org/springframework/security/web/util/matcher/RegexRequestMatcher.html[`RegexRequestMatcher`] to respect this rule, like so:
+
+.Match with Regex
+====
+.Java
+[source,java,role="primary"]
+----
+http
+    .authorizeHttpRequests((authorize) -> authorize
+        .requestMatchers(RegexRequestMatcher.regexMatcher("/resource/[A-Za-z0-9]+")).hasAuthority("USER")
+        .anyRequest().denyAll()
+    )
+----
+
 .Kotlin
 [source,kotlin,role="secondary"]
 ----
-@Bean
-open fun web(http: HttpSecurity): SecurityFilterChain {
-    http {
-        authorizeHttpRequests {
-            shouldFilterAllDispatcherTypes = false
-            authorize(anyRequest, authenticated)
-        }
+http {
+    authorizeHttpRequests {
+        authorize(RegexRequestMatcher.regexMatcher("/resource/[A-Za-z0-9]+"), hasAuthority("USER"))
+        authorize(anyRequest, denyAll)
+    }
+}
+----
+
+.Xml
+[source,xml,role="secondary"]
+----
+<http>
+    <intercept-url request-matcher="regex" pattern="/resource/[A-Za-z0-9]+" access="hasAuthority('USER')"/>
+    <intercept-url pattern="/**" access="denyAll"/>
+</http>
+----
+====
+
+[[match-by-httpmethod]]
+=== Matching By Http Method
+
+You can also match rules by HTTP method.
+One place where this is handy is when authorizing by permissions granted, like being granted a `read` or `write` privilege.
+
+To require all ``GET``s to have the `read` permission and all ``POST``s to have the `write` permission, you can do something like this:
+
+.Match by HTTP Method
+====
+.Java
+[source,java,role="primary"]
+----
+http
+    .authorizeHttpRequests((authorize) -> authorize
+        .requestMatchers(HttpMethod.GET).hasAuthority("read")
+        .requestMatchers(HttpMethod.POST).hasAuthority("write")
+        .anyRequest().denyAll()
+    )
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+http {
+    authorizeHttpRequests {
+        authorize(HttpMethod.GET, hasAuthority("read"))
+        authorize(HttpMethod.POST, hasAuthority("write"))
+        authorize(anyRequest, denyAll)
+    }
+}
+----
+
+.Xml
+[source,xml,role="secondary"]
+----
+<http>
+    <intercept-url http-method="GET" pattern="/**" access="hasAuthority('read')"/>
+    <intercept-url http-method="POST" pattern="/**" access="hasAuthority('write')"/>
+    <intercept-url pattern="/**" access="denyAll"/>
+</http>
+----
+====
+
+These authorization rules should read as: "if the request is a GET, then require `read` permission; else, if the request is a POST, then require `write` permission; else, deny the request"
+
+[TIP]
+Denying the request by default is a healthy security practice since it turns the set of rules into an allow list.
+
+Once authorized, you can test it using xref:servlet/test/method.adoc#test-method-withmockuser[Security's test support] in the following way:
+
+.Test Http Method Authorization
+====
+.Java
+[source,java,role="primary"]
+----
+@WithMockUser(authorities="read")
+@Test
+void getWhenReadAuthorityThenAuthorized() {
+    this.mvc.perform(get("/any"))
+        .andExpect(status().isOk());
+}
+
+@WithMockUser
+@Test
+void getWhenNoReadAuthorityThenForbidden() {
+    this.mvc.perform(get("/any"))
+        .andExpect(status().isForbidden());
+}
+
+@WithMockUser(authorities="write")
+@Test
+void postWhenWriteAuthorityThenAuthorized() {
+    this.mvc.perform(post("/any").with(csrf()))
+        .andExpect(status().isOk())
+}
+
+@WithMockUser(authorities="read")
+@Test
+void postWhenNoWriteAuthorityThenForbidden() {
+    this.mvc.perform(get("/any").with(csrf()))
+        .andExpect(status().isForbidden());
+}
+----
+====
+
+[[match-by-dispatcher-type]]
+=== Matching By Dispatcher Type
+
+[NOTE]
+This feature is not currently supported in XML
+
+As stated earlier, Spring Security <<_all_dispatches_are_authorized, authorizes all dispatcher types by default>>.
+And even though xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontext[the security context] established on the `REQUEST` dispatch carries over to subsequent dispatches, subtle mismatches can sometimes cause an unexpected `AccessDeniedException`.
+
+To address that, you can configure Spring Security Java configuration to allow dispatcher types like `FORWARD` and `ERROR`, like so:
+
+.Match by Dispatcher Type
+====
+.Java
+[source,java,role="secondary"]
+----
+http
+    .authorizeHttpRequests((authorize) -> authorize
+        .dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
+        .requestMatchers("/endpoint").permitAll()
+        .anyRequest().denyAll()
+    )
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+http {
+    authorizeHttpRequests {
+        authorize(DispatcherType.FORWARD, permitAll)
+        authorize(DispatcherType.ERROR, permitAll)
+        authorize("/endpoint", permitAll)
+        authorize(anyRequest, denyAll)
     }
-    return http.build()
 }
 ----
 ====
 
-Instead of setting `shouldFilterAllDispatcherTypes` to `false`, the recommended approach is to customize authorization on the dispatcher types.
-For example, you may want to grant all access on requests with dispatcher type `ASYNC` or `FORWARD`.
+[[match-by-custom]]
+=== Using a Custom Matcher
+
+[NOTE]
+This feature is not currently supported in XML
 
-.Permit ASYNC and FORWARD dispatcher type
+In Java configuration, you can create your own {security-api-url}org/springframework/security/web/util/matcher/RequestMatcher.html[`RequestMatcher`] and supply it to the DSL like so:
+
+.Authorize by Dispatcher Type
+====
+.Java
+[source,java,role="secondary"]
+----
+RequestMatcher printview = (request) -> request.getParameter("print") != null;
+http
+    .authorizeHttpRequests((authorize) -> authorize
+        .requestMatchers(printview).hasAuthority("print")
+        .anyRequest().authenticated()
+    )
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+val printview: RequestMatcher = { (request) -> request.getParameter("print") != null }
+http {
+    authorizeHttpRequests {
+        authorize(printview, hasAuthority("print"))
+        authorize(anyRequest, authenticated)
+    }
+}
+----
+====
+
+[TIP]
+Because {security-api-url}org/springframework/security/web/util/matcher/RequestMatcher.html[`RequestMatcher`] is a functional interface, you can supply it as a lambda in the DSL.
+However, if you want to extract values from the request, you will need to have a concrete class since that requires overriding a `default` method.
+
+Once authorized, you can test it using xref:servlet/test/method.adoc#test-method-withmockuser[Security's test support] in the following way:
+
+.Test Custom Authorization
 ====
 .Java
 [source,java,role="primary"]
 ----
+@WithMockUser(authorities="print")
+@Test
+void printWhenPrintAuthorityThenAuthorized() {
+    this.mvc.perform(get("/any?print"))
+        .andExpect(status().isOk());
+}
+
+@WithMockUser
+@Test
+void printWhenNoPrintAuthorityThenForbidden() {
+    this.mvc.perform(get("/any?print"))
+        .andExpect(status().isForbidden());
+}
+----
+====
+
+[[authorize-requests]]
+== Authorizing Requests
+
+Once a request is matched, you can authorize it in several ways <<match-requests, already seen>> like `permitAll`, `denyAll`, and `hasAuthority`.
+
+As a quick summary, here are the authorization rules built into the DSL:
+
+* `permitAll` - The request requires no authorization and is a public endpoint; note that in this case, xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[the `Authentication`] is never retrieved from the session
+* `denyAll` - The request is not allowed under any circumstances; note that in this case, the `Authentication` is never retrieved from the session
+* `hasAuthority` - The request requires that the `Authentication` have xref:servlet/authorization/architecture.adoc#authz-authorities[a `GrantedAuthority`] that matches the given value
+* `hasRole` - A shortcut for `hasAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
+* `hasAnyAuthority` - The request requires that the `Authentication` have a `GrantedAuthority` that matches any of the given values
+* `hasAnyRole` - A shortcut for `hasAnyAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
+* `access` - The request uses this custom `AuthorizationManager` to determine access
+
+Having now learned the patterns, rules, and how they can be paired together, you should be able to understand what is going on in this more complex example:
+
+.Authorize Requests
+====
+.Java
+[source,java,role="primary"]
+----
+import static jakarta.servlet.DispatcherType.*;
+
+import static org.springframework.security.authorization.AuthorizationManagers.allOf;
+import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasAuthority;
+import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
+
 @Bean
 SecurityFilterChain web(HttpSecurity http) throws Exception {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .dispatcherTypeMatchers(DispatcherType.ASYNC, DispatcherType.FORWARD).permitAll()
-            .anyRequest().authenticated()
-        )
-        // ...
+	http
+		// ...
+		.authorizeHttpRequests(authorize -> authorize                                  // <1>
+            .dispatcherTypeMatchers(FORWARD, ERROR).permitAll() // <2>
+			.requestMatchers("/static/**", "/signup", "/about").permitAll()         // <3>
+			.requestMatchers("/admin/**").hasRole("ADMIN")                             // <4>
+			.requestMatchers("/db/**").access(allOf(hasAuthority('db'), hasRole('ADMIN')))   // <5>
+			.anyRequest().denyAll()                                                // <6>
+		);
 
-    return http.build();
+	return http.build();
+}
+----
+====
+<1> There are multiple authorization rules specified.
+Each rule is considered in the order they were declared.
+<2> Dispatches `FORWARD` and `ERROR` are permitted to allow {spring-framework-reference-url}web.html#spring-web[Spring MVC] to render views and Spring Boot to render errors
+<3> We specified multiple URL patterns that any user can access.
+Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about".
+<4> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN".
+You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix.
+<5> Any URL that starts with "/db/" requires the user to have both been granted the "db" permission as well as be a "ROLE_ADMIN".
+You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
+<6> Any URL that has not already been matched on is denied access.
+This is a good strategy if you do not want to accidentally forget to update your authorization rules.
+
+[[remote-authorization-manager]]
+=== Use an Authorization Database, Policy Agent, or Other Service
+If you want to configure Spring Security to use a separate service for authorization, you can create your own `AuthorizationManager` and match it to `anyRequest`.
+
+First, your `AuthorizationManager` may look something like this:
+
+.Open Policy Agent Authorization Manager
+====
+.Java
+[source,java,role="primary"]
+----
+@Component
+public final class OpenPolicyAgentAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
+    @Override
+    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
+        // make request to Open Policy Agent
+    }
 }
 ----
+====
+
+Then, you can wire it into Spring Security in the following way:
+
+.Any Request Goes to Remote Service
+====
+.Java
+[source,java,role="primary"]
+----
+@Bean
+SecurityFilterChain web(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> authz) throws Exception {
+	http
+		// ...
+		.authorizeHttpRequests((authorize) -> authorize
+            .anyRequest().access(authz)
+		);
+
+	return http.build();
+}
+----
+====
+
+[[favor-permitall]]
+=== Favor `permitAll` over `ignoring`
+When you have static resources it can be tempting to configure the filter chain to ignore these values.
+A more secure approach is to permit them using `permitAll` like so:
+
+.Permit Static Resources
+====
+.Java
+[source,java,role="secondary"]
+----
+http
+    .authorizeHttpRequests((authorize) -> authorize
+        .requestMatchers("/css/**").permitAll()
+        .anyRequest().authenticated()
+    )
+----
+
 .Kotlin
 [source,kotlin,role="secondary"]
 ----
-@Bean
-open fun web(http: HttpSecurity): SecurityFilterChain {
-    http {
-        authorizeHttpRequests {
-            authorize(DispatcherTypeRequestMatcher(DispatcherType.ASYNC, DispatcherType.FORWARD), permitAll)
-            authorize(anyRequest, authenticated)
-        }
+http {
+    authorizeHttpRequests {
+        authorize("/css/**", permitAll)
+        authorize(anyRequest, authenticated)
     }
-    return http.build()
 }
 ----
 ====
 
-You can also customize it to require a specific role for a dispatcher type:
+It's more secure because even with static resources it's important to write secure headers, which Spring Security cannot do if the request is ignored.
+
+In this past, this came with a performance tradeoff since the session was consulted by Spring Security on every request.
+As of Spring Security 6, however, the session is no longer pinged unless required by the authorization rule.
+Because the performance impact is now addressed, Spring Security recommends using at least `permitAll` for all requests.
+
+[[migrate-authorize-requests]]
+== Migrating from `authorizeRequests`
+
+[NOTE]
+`AuthorizationFilter` supersedes {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`].
+To remain backward compatible, `FilterSecurityInterceptor` remains the default.
+This section discusses how `AuthorizationFilter` works and how to override the default configuration.
+
+The {security-api-url}org/springframework/security/web/access/intercept/AuthorizationFilter.html[`AuthorizationFilter`] provides xref:servlet/authorization/index.adoc#servlet-authorization[authorization] for ``HttpServletRequest``s.
+It is inserted into the xref:servlet/architecture.adoc#servlet-filterchainproxy[FilterChainProxy] as one of the xref:servlet/architecture.adoc#servlet-security-filters[Security Filters].
+
+You can override the default when you declare a `SecurityFilterChain`.
+Instead of using {security-api-url}org/springframework/security/config/annotation/web/builders/HttpSecurity.html#authorizeRequests()[`authorizeRequests`], use `authorizeHttpRequests`, like so:
 
-.Require ADMIN for Dispatcher Type ERROR
+.Use authorizeHttpRequests
 ====
 .Java
 [source,java,role="primary"]
 ----
 @Bean
-SecurityFilterChain web(HttpSecurity http) throws Exception {
+SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
     http
         .authorizeHttpRequests((authorize) -> authorize
-            .dispatcherTypeMatchers(DispatcherType.ERROR).hasRole("ADMIN")
-            .anyRequest().authenticated()
+            .anyRequest().authenticated();
         )
         // ...
 
     return http.build();
 }
 ----
+====
+
+This improves on `authorizeRequests` in a number of ways:
+
+1. Uses the simplified `AuthorizationManager` API instead of metadata sources, config attributes, decision managers, and voters.
+This simplifies reuse and customization.
+2. Delays `Authentication` lookup.
+Instead of the authentication needing to be looked up for every request, it will only look it up in requests where an authorization decision requires authentication.
+3. Bean-based configuration support.
+
+When `authorizeHttpRequests` is used instead of `authorizeRequests`, then {security-api-url}org/springframework/security/web/access/intercept/AuthorizationFilter.html[`AuthorizationFilter`] is used instead of {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`].
+
+=== Migrating Expressions
+
+Where possible, it is recommended that you use type-safe authorization managers instead of SpEL.
+For Java configuration, {security-api-url}org/springframework/security/web/access/expression/WebExpressionAuthorizationManager.html[`WebExpressionAuthorizationManager`] is available to help migrate legacy SpEL.
+
+To use `WebExpressionAuthorizationManager`, you can construct one with the expression you are trying to migrate, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+.requestMatchers("/test/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') && hasRole('USER')"))
+----
+
 .Kotlin
 [source,kotlin,role="secondary"]
 ----
-@Bean
-open fun web(http: HttpSecurity): SecurityFilterChain {
-    http {
-        authorizeHttpRequests {
-            authorize(DispatcherTypeRequestMatcher(DispatcherType.ERROR), hasRole("ADMIN"))
-            authorize(anyRequest, authenticated)
-        }
-    }
-    return http.build()
-}
+.requestMatchers("/test/**").access(WebExpressionAuthorizationManager("hasRole('ADMIN') && hasRole('USER')"))
 ----
 ====
 
-== Request Matchers
+If you are referring to a bean in your expression like so: `@webSecurity.check(authentication, request)`, it's recommended that you instead call the bean directly, which will look something like the following:
 
-The `RequestMatcher` interface is used to determine if a request matches a given rule.
-We use `securityMatchers` to determine if a given `HttpSecurity` should be applied to a given request.
+====
+.Java
+[source,java,role="primary"]
+----
+.requestMatchers("/test/**").access((authentication, context) ->
+    new AuthorizationDecision(webSecurity.check(authentication.get(), context.getRequest())))
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+.requestMatchers("/test/**").access((authentication, context): AuthorizationManager<RequestAuthorizationContext> ->
+    AuthorizationDecision(webSecurity.check(authentication.get(), context.getRequest())))
+----
+====
+
+For complex instructions that include bean references as well as other expressions, it is recommended that you change those to implement `AuthorizationManager` and refer to them by calling `.access(AuthorizationManager)`.
+
+If you are not able to do that, you can configure a {security-api-url}org/springframework/security/web/access/expression/DefaultHttpSecurityExpressionHandler.html[`DefaultHttpSecurityExpressionHandler`] with a bean resolver and supply that to `WebExpressionAuthorizationManager#setExpressionhandler`.
+
+[[security-matchers]]
+== Security Matchers
+
+The {security-api-url}org/springframework/security/web/util/matcher/RequestMatcher.html[`RequestMatcher`] interface is used to determine if a request matches a given rule.
+We use `securityMatchers` to determine if xref:servlet/configuration/java.adoc#jc-httpsecurity[a given `HttpSecurity`] should be applied to a given request.
 The same way, we can use `requestMatchers` to determine the authorization rules that we should apply to a given request.
 Look at the following example:
 
@@ -336,7 +871,7 @@ open class SecurityConfig {
 <3> Allow access to URLs that start with `/admin/` to users with the `ADMIN` role
 <4> Any other request that doesn't match the rules above, will require authentication
 
-The `securityMatcher(s)` and `requestMatcher(s)` methods will decide which `RequestMatcher` implementation fits best for your application: If Spring MVC is in the classpath, then `MvcRequestMatcher` will be used, otherwise, `AntPathRequestMatcher` will be used.
+The `securityMatcher(s)` and `requestMatcher(s)` methods will decide which `RequestMatcher` implementation fits best for your application: If {spring-framework-reference-url}web.html#spring-web[Spring MVC] is in the classpath, then {security-api-url}org/springframework/security/web/servlet/util/matcher/MvcRequestMatcher.html[`MvcRequestMatcher`] will be used, otherwise, {security-api-url}org/springframework/security/web/servlet/util/matcher/AntPathRequestMatcher.html[`AntPathRequestMatcher`] will be used.
 You can read more about the Spring MVC integration xref:servlet/integrations/mvc.adoc[here].
 
 If you want to use a specific `RequestMatcher`, just pass an implementation to the `securityMatcher` and/or `requestMatcher` methods:
@@ -409,45 +944,7 @@ open class SecurityConfig {
 <4> Allow access to URLs that start with `/admin/` to users with the `ADMIN` role, using `RegexRequestMatcher`
 <5> Allow access to URLs that match the `MyCustomRequestMatcher` to users with the `SUPERVISOR` role, using a custom `RequestMatcher`
 
-== Expressions
-
-It is recommended that you use type-safe authorization managers instead of SpEL.
-However, `WebExpressionAuthorizationManager` is available to help migrate legacy SpEL.
-
-To use `WebExpressionAuthorizationManager`, you can construct one with the expression you are trying to migrate, like so:
-
-====
-.Java
-[source,java,role="primary"]
-----
-.requestMatchers("/test/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') && hasRole('USER')"))
-----
-
-.Kotlin
-[source,kotlin,role="secondary"]
-----
-.requestMatchers("/test/**").access(WebExpressionAuthorizationManager("hasRole('ADMIN') && hasRole('USER')"))
-----
-====
-
-If you are referring to a bean in your expression like so: `@webSecurity.check(authentication, request)`, it's recommended that you instead call the bean directly, which will look something like the following:
-
-====
-.Java
-[source,java,role="primary"]
-----
-.requestMatchers("/test/**").access((authentication, context) ->
-    new AuthorizationDecision(webSecurity.check(authentication.get(), context.getRequest())))
-----
-
-.Kotlin
-[source,kotlin,role="secondary"]
-----
-.requestMatchers("/test/**").access((authentication, context): AuthorizationManager<RequestAuthorizationContext> ->
-    AuthorizationDecision(webSecurity.check(authentication.get(), context.getRequest())))
-----
-====
-
-For complex instructions that include bean references as well as other expressions, it is recommended that you change those to implement `AuthorizationManager` and refer to them by calling `.access(AuthorizationManager)`.
+== Further Reading
 
-If you are not able to do that, you can configure a `DefaultHttpSecurityExpressionHandler` with a bean resolver and supply that to `WebExpressionAuthorizationManager#setExpressionhandler`.
+Now that you have secured your application's requests, consider xref:servlet/authorization/method-security.adoc[securing its methods].
+You can also read further on xref:servlet/test/index.adoc[testing your application] or on integrating Spring Security with other aspects of you application like xref:servlet/integrations/data.adoc[the data layer] or xref:servlet/integrations/observability.adoc[tracing and metrics].

+ 0 - 183
docs/modules/ROOT/pages/servlet/authorization/authorize-requests.adoc

@@ -1,183 +0,0 @@
-[[servlet-authorization-filtersecurityinterceptor]]
-= Authorize HttpServletRequest with FilterSecurityInterceptor
-:figures: servlet/authorization
-
-[NOTE]
-====
-`FilterSecurityInterceptor` is in the process of being replaced by xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`].
-Consider using that instead.
-====
-
-This section builds on xref:servlet/architecture.adoc#servlet-architecture[Servlet Architecture and Implementation] by digging deeper into how xref:servlet/authorization/index.adoc#servlet-authorization[authorization] works within Servlet-based applications.
-
-The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides xref:servlet/authorization/index.adoc#servlet-authorization[authorization] for `HttpServletRequest` instances.
-It is inserted into the xref:servlet/architecture.adoc#servlet-filterchainproxy[FilterChainProxy] as one of the xref:servlet/architecture.adoc#servlet-security-filters[Security Filters].
-
-The following image shows the role of `FilterSecurityInterceptor`:
-
-.Authorize HttpServletRequest
-image::{figures}/filtersecurityinterceptor.png[]
-
-image:{icondir}/number_1.png[] The `FilterSecurityInterceptor` obtains an xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
-image:{icondir}/number_2.png[] `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`.
-image:{icondir}/number_3.png[] It passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s.
-image:{icondir}/number_4.png[] It passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`.
-image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown.
-In this case, the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] handles the `AccessDeniedException`.
-image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the xref:servlet/architecture.adoc#servlet-filters-review[`FilterChain`], which lets the application process normally.
-
-// configuration (xml/java)
-
-By default, Spring Security's authorization requires all requests to be authenticated.
-The following listing shows the explicit configuration:
-
-[[servlet-authorize-requests-defaults]]
-.Every Request Must be Authenticated
-====
-.Java
-[source,java,role="primary"]
-----
-@Bean
-public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
-	http
-		// ...
-		.authorizeRequests(authorize -> authorize
-			.anyRequest().authenticated()
-		);
-	return http.build();
-}
-----
-
-.XML
-[source,xml,role="secondary"]
-----
-<http>
-	<!-- ... -->
-	<intercept-url pattern="/**" access="authenticated"/>
-</http>
-----
-
-.Kotlin
-[source,kotlin,role="secondary"]
-----
-@Bean
-open fun filterChain(http: HttpSecurity): SecurityFilterChain {
-    http {
-        // ...
-        authorizeRequests {
-            authorize(anyRequest, authenticated)
-        }
-    }
-    return http.build()
-}
-----
-====
-
-We can configure Spring Security to have different rules by adding more rules in order of precedence:
-
-.Authorize Requests
-====
-.Java
-[source,java,role="primary"]
-----
-@Bean
-public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
-	http
-		// ...
-		.authorizeRequests(authorize -> authorize                                  // <1>
-			.requestMatchers("/resources/**", "/signup", "/about").permitAll()         // <2>
-			.requestMatchers("/admin/**").hasRole("ADMIN")                             // <3>
-			.requestMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")   // <4>
-			.anyRequest().denyAll()                                                // <5>
-		);
-	return http.build();
-}
-----
-
-.XML
-[source,xml,role="secondary"]
-----
-<http> <!--1-->
-	<!-- ... -->
-	<!--2-->
-	<intercept-url pattern="/resources/**" access="permitAll"/>
-	<intercept-url pattern="/signup" access="permitAll"/>
-	<intercept-url pattern="/about" access="permitAll"/>
-
-	<intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/> <!--3-->
-	<intercept-url pattern="/db/**" access="hasRole('ADMIN') and hasRole('DBA')"/> <!--4-->
-	<intercept-url pattern="/**" access="denyAll"/> <!--5-->
-</http>
-----
-
-.Kotlin
-[source,kotlin,role="secondary"]
-----
-@Bean
-open fun filterChain(http: HttpSecurity): SecurityFilterChain {
-   http {
-        authorizeRequests { // <1>
-            authorize("/resources/**", permitAll) // <2>
-            authorize("/signup", permitAll)
-            authorize("/about", permitAll)
-
-            authorize("/admin/**", hasRole("ADMIN")) // <3>
-            authorize("/db/**", "hasRole('ADMIN') and hasRole('DBA')") // <4>
-            authorize(anyRequest, denyAll) // <5>
-        }
-    }
-    return http.build()
-}
-----
-====
-<1> There are multiple authorization rules specified.
-Each rule is considered in the order they were declared.
-<2> We specified multiple URL patterns that any user can access.
-Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about".
-<3> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN".
-You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix.
-<4> Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA".
-You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
-<5> Any URL that has not already been matched on is denied access.
-This is a good strategy if you do not want to accidentally forget to update your authorization rules.
-====
-
-
-[[filtersecurityinterceptor-every-request]]
-== Configure FilterSecurityInterceptor with Dispatcher Types
-
-By default, the `FilterSecurityInterceptor` applies to every request.
-This means that if a request is dispatched from a request that was already filtered, the `FilterSecurityInterceptor` will perform the same authorization checks on the dispatched request.
-In some scenarios, you may not want to apply authorization on some dispatcher types:
-
-.Permit ASYNC and ERROR dispatcher types
-====
-.Java
-[source,java,role="primary"]
-----
-@Bean
-SecurityFilterChain web(HttpSecurity http) throws Exception {
-    http
-        .authorizeRequests((authorize) -> authorize
-            .dispatcherTypeMatchers(DispatcherType.ASYNC, DispatcherType.ERROR).permitAll()
-            .anyRequest.authenticated()
-        )
-        // ...
-
-    return http.build();
-}
-----
-.XML
-[source,xml]
-----
-<http auto-config="true">
-    <intercept-url request-matcher-ref="dispatcherTypeMatcher" access="permitAll" />
-    <intercept-url pattern="/**" access="authenticated"/>
-</http>
-
-<b:bean id="dispatcherTypeMatcher" class="org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher">
-    <b:constructor-arg value="ASYNC"/>
-    <b:constructor-arg value="ERROR"/>
-</b:bean>
-----
-====

+ 4 - 3
docs/modules/ROOT/pages/servlet/authorization/index.adoc

@@ -2,11 +2,12 @@
 = Authorization
 :page-section-summary-toc: 1
 
+Having established xref:servlet/authentication/index.adoc[how users will authenticate], you also need to configure your application's authorization rules.
+
 The advanced authorization capabilities within Spring Security represent one of the most compelling reasons for its popularity.
 Irrespective of how you choose to authenticate (whether using a Spring Security-provided mechanism and provider or integrating with a container or other non-Spring Security authentication authority), the authorization services can be used within your application in a consistent and simple way.
 
-In this part, we explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I.
-We then move on to explore how to fine-tune authorization through the use of domain access control lists.
-
+You should consider attaching authorization rules to xref:servlet/authorization/authorize-http-requests.adoc[request URIs] and xref:servlet/authorization/method-security.adoc[methods] to begin.
+Below there is also wealth of detail about xref:servlet/authorization/architecture.adoc[how Spring Security authorization works] and how, having established a basic model, it can be fine-tuned.
 
 

File diff suppressed because it is too large
+ 700 - 216
docs/modules/ROOT/pages/servlet/authorization/method-security.adoc


+ 0 - 143
docs/modules/ROOT/pages/servlet/authorization/secure-objects.adoc

@@ -1,143 +0,0 @@
-
-[[secure-object-impls]]
-= Secure Object Implementations
-
-This section covers how Spring Security handles Secure Object implementations.
-
-[[aop-alliance]]
-== AOP Alliance (MethodInvocation) Security Interceptor
-Prior to Spring Security 2.0, securing `MethodInvocation` instances needed a lot of boiler plate configuration.
-Now the recommended approach for method security is to use xref:servlet/configuration/xml-namespace.adoc#ns-method-security[namespace configuration].
-This way, the method security infrastructure beans are configured automatically for you, so you need not know about the implementation classes.
-We provide only a quick overview of the classes that are involved here.
-
-Method security is enforced by using a `MethodSecurityInterceptor`, which secures `MethodInvocation` instances.
-Depending on the configuration approach, an interceptor may be specific to a single bean or shared between multiple beans.
-The interceptor uses a `MethodSecurityMetadataSource` instance to obtain the configuration attributes that apply to a particular method invocation.
-`MapBasedMethodSecurityMetadataSource` is used to store configuration attributes keyed by method names (which can be wildcarded) and will be used internally when the attributes are defined in the application context using the `<intercept-methods>` or `<protect-point>` elements.
-Other implementations are used to handle annotation-based configuration.
-
-=== Explicit MethodSecurityInterceptor Configuration
-You can configure a `MethodSecurityInterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms:
-
-====
-[source,xml]
-----
-<bean id="bankManagerSecurity" class=
-	"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
-<property name="authenticationManager" ref="authenticationManager"/>
-<property name="accessDecisionManager" ref="accessDecisionManager"/>
-<property name="afterInvocationManager" ref="afterInvocationManager"/>
-<property name="securityMetadataSource">
-	<sec:method-security-metadata-source>
-	<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
-	<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
-	</sec:method-security-metadata-source>
-</property>
-</bean>
-----
-====
-
-[[aspectj]]
-== AspectJ (JoinPoint) Security Interceptor
-The AspectJ security interceptor is very similar to the AOP Alliance security interceptor discussed in the previous section.
-We discuss only the differences in this section.
-
-The AspectJ interceptor is named `AspectJSecurityInterceptor`.
-Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor through proxying, the `AspectJSecurityInterceptor` is woven in through the AspectJ compiler.
-It would not be uncommon to use both types of security interceptors in the same application, with `AspectJSecurityInterceptor` being used for domain object instance security and the AOP Alliance `MethodSecurityInterceptor` being used for services layer security.
-
-We first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context:
-
-====
-[source,xml]
-----
-<bean id="bankManagerSecurity" class=
-	"org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
-<property name="authenticationManager" ref="authenticationManager"/>
-<property name="accessDecisionManager" ref="accessDecisionManager"/>
-<property name="afterInvocationManager" ref="afterInvocationManager"/>
-<property name="securityMetadataSource">
-	<sec:method-security-metadata-source>
-	<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
-	<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
-	</sec:method-security-metadata-source>
-</property>
-</bean>
-----
-====
-
-The two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` instances rather than an AOP library-specific class.
-Your access decisions have access to the relevant AOP library-specific invocation (`MethodInvocation` or `JoinPoint`) and can consider a range of additional criteria (such as method arguments) when making access decisions.
-
-Next, you need to define an AspectJ `aspect`, as the following example shows:
-
-====
-[source,java]
-----
-
-package org.springframework.security.samples.aspectj;
-
-import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
-import org.springframework.security.access.intercept.aspectj.AspectJCallback;
-import org.springframework.beans.factory.InitializingBean;
-
-public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
-
-	private AspectJSecurityInterceptor securityInterceptor;
-
-	pointcut domainObjectInstanceExecution(): target(PersistableEntity)
-		&& execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
-
-	Object around(): domainObjectInstanceExecution() {
-		if (this.securityInterceptor == null) {
-			return proceed();
-		}
-
-		AspectJCallback callback = new AspectJCallback() {
-			public Object proceedWithObject() {
-				return proceed();
-			}
-		};
-
-		return this.securityInterceptor.invoke(thisJoinPoint, callback);
-	}
-
-	public AspectJSecurityInterceptor getSecurityInterceptor() {
-		return securityInterceptor;
-	}
-
-	public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
-		this.securityInterceptor = securityInterceptor;
-	}
-
-	public void afterPropertiesSet() throws Exception {
-		if (this.securityInterceptor == null)
-			throw new IllegalArgumentException("securityInterceptor required");
-		}
-	}
-}
-----
-====
-
-
-In the preceding example, the security interceptor is applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like).
-For those curious, `AspectJCallback` is needed because the `proceed();` statement has special meaning only within an `around()` body.
-The `AspectJSecurityInterceptor` calls this anonymous `AspectJCallback` class when it wants the target object to continue.
-
-You need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`.
-The following example shows a bean declaration that achieves this:
-
-====
-[source,xml]
-----
-
-<bean id="domainObjectInstanceSecurityAspect"
-	class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
-	factory-method="aspectOf">
-<property name="securityInterceptor" ref="bankManagerSecurity"/>
-</bean>
-----
-====
-
-Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`), and they have the security interceptor applied.

+ 1 - 1
docs/modules/ROOT/pages/servlet/oauth2/resource-server/index.adoc

@@ -27,7 +27,7 @@ The figure above builds off our xref:servlet/architecture.adoc#servlet-securityf
 
 image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource for which the user is not authorized.
 
-image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`.
+image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`.
 
 image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates _Start Authentication_.
 The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`], which sends a `WWW-Authenticate` header.

+ 1 - 1
docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc

@@ -16,7 +16,7 @@ The figure above builds off our xref:servlet/architecture.adoc#servlet-securityf
 
 image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource, for which it is not authorized.
 
-image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`.
+image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`.
 
 image:{icondir}/number_3.png[] Since the user lacks authorization, the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates _Start Authentication_.
 The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`], which redirects to <<servlet-saml2login-sp-initiated-factory,the `<saml2:AuthnRequest>` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`.

Some files were not shown because too many files changed in this diff