Register FilterChainProxy for All Dispatcher Types Migration Steps

Closes gh-12186
This commit is contained in:
Marcus Da Coregio 2022-11-10 10:46:09 -03:00 committed by Josh Cummings
parent b81fbf024b
commit 9bc38ed318
1 changed files with 141 additions and 1 deletions

View File

@ -1374,6 +1374,7 @@ http {
---- ----
==== ====
[[switch-filter-all-dispatcher-types]]
==== Switch to filter all dispatcher types ==== Switch to filter all dispatcher types
Spring Security 5.8 and earlier only xref:servlet/authorization/architecture.adoc[perform authorization] once per request. Spring Security 5.8 and earlier only xref:servlet/authorization/architecture.adoc[perform authorization] once per request.
@ -1384,7 +1385,7 @@ As such, in 6.0, Spring Security changes this default.
So, finally, change your authorization rules to filter all dispatcher types. So, finally, change your authorization rules to filter all dispatcher types.
To do this, change: To do this, you should change:
==== ====
.Java .Java
@ -1464,6 +1465,145 @@ http {
---- ----
==== ====
And, the `FilterChainProxy` should be registered for all dispatcher types as well.
If you are using Spring Boot, https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.security.spring.security.filter.dispatcher-types[you have to change the `spring.security.filter.dispatcher-types` property] to include all dispatcher types:
====
.application.properties
[source,properties,role="primary"]
----
spring.security.filter.dispatcher-types=request,async,error,forward,include
----
====
If you are xref::servlet/configuration/java.adoc#_abstractsecuritywebapplicationinitializer[using the `AbstractSecurityWebApplicationInitializer`] you should override the `getSecurityDispatcherTypes` method and return all dispatcher types:
====
.Java
[source,java,role="primary"]
----
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
@Override
protected EnumSet<DispatcherType> getSecurityDispatcherTypes() {
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.FORWARD,
DispatcherType.FORWARD, DispatcherType.INCLUDE);
}
}
----
====
===== Permit `FORWARD` when using Spring MVC
If you are using {spring-framework-reference-url}/web.html#mvc-viewresolver[Spring MVC to resolve view names], you will need to permit `FORWARD` requests.
This is because when Spring MVC detects a mapping between view name and the actual views, it will perform a forward to the view.
As we saw on the <<switch-filter-all-dispatcher-types,previous section>>, Spring Security 6.0 will apply authorization to `FORWARD` requests by default.
Consider the following common configuration:
====
.Java
[source,java,role="primary"]
----
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.shouldFilterAllDispatcherTypes(true)
.requestMatchers("/").authenticated()
.anyRequest().denyAll()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
));
return http.build();
}
----
====
and one of the following equivalents MVC view mapping configurations:
====
.Java
[source,java,role="primary"]
----
@Controller
public class MyController {
@GetMapping("/login")
public String login() {
return "login";
}
}
----
====
====
.Java
[source,java,role="primary"]
----
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
----
====
With either configuration, when there is a request to `/login`, Spring MVC will perform a *forward* to the view `login`, which, with the default configuration, is under `src/main/resources/templates/login.html` path.
The security configuration permits requests to `/login` but every other request will be denied, including the `FORWARD` request to the view under `/templates/login.html`.
To fix this, you should configure Spring Security to permit `FORWARD` requests:
====
.Java
[source,java,role="primary"]
----
http
.authorizeHttpRequests((authorize) -> authorize
.shouldFilterAllDispatcherTypes(true)
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
.anyRequest().denyAll()
)
// ...
----
.Kotlin
[source,kotlin,role="secondary"]
----
http {
authorizeHttpRequests {
shouldFilterAllDispatcherTypes = true
authorize(DispatcherTypeRequestMatcher(DispatcherType.FORWARD), permitAll)
authorize(anyRequest, denyAll)
}
}
----
.Xml
[source,xml,role="secondary"]
----
<http filter-all-dispatcher-types="true" use-authorization-manager="true">
<intercept-url request-matcher-ref="forwardRequestMatcher" access="permitAll()" />
<!-- ... -->
<intercept-url pattern="/**" access="denyAll"/>
</http>
<bean name="forwardRequestMatcher" class="org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher">
<constructor-arg value="FORWARD"/>
</bean>
----
====
==== Replace any custom filter-security ``AccessDecisionManager``s ==== Replace any custom filter-security ``AccessDecisionManager``s
Your application may have a custom {security-api-url}org/springframework/security/access/AccessDecisionManager.html[`AccessDecisionManager`] or {security-api-url}org/springframework/security/access/AccessDecisionVoter.html[`AccessDecisionVoter`] arrangement. Your application may have a custom {security-api-url}org/springframework/security/access/AccessDecisionManager.html[`AccessDecisionManager`] or {security-api-url}org/springframework/security/access/AccessDecisionVoter.html[`AccessDecisionVoter`] arrangement.