Register FilterChainProxy for All Dispatcher Types Migration Steps
Closes gh-12186
This commit is contained in:
		
							parent
							
								
									b81fbf024b
								
							
						
					
					
						commit
						9bc38ed318
					
				|  | @ -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. | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue