| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 | 
							- = Reactive Migrations
 
- If you have already performed the xref:migration/index.adoc[initial migration steps] for your Reactive application, you're now ready to perform steps specific to Reactive applications.
 
- == Exploit Protection Migrations
 
- The following steps relate to changes around how to configure CSRF.
 
- === Configure `tokenFromMultipartDataEnabled`
 
- In Spring Security 5.8, the method `tokenFromMultipartDataEnabled` was deprecated in favor of `ServerCsrfTokenRequestAttributeHandler#setTokenFromMultipartDataEnabled`.
 
- To address the deprecation, the following code:
 
- .Configure `tokenFromMultipartDataEnabled` with DSL
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
 
- 	http
 
- 		// ...
 
- 		.csrf((csrf) -> csrf
 
- 			.tokenFromMultipartDataEnabled(true)
 
- 		);
 
- 	return http.build();
 
- }
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
 
- 	return http {
 
- 		// ...
 
- 		csrf {
 
- 			tokenFromMultipartDataEnabled = true
 
- 		}
 
- 	}
 
- }
 
- ----
 
- ====
 
- can be replaced with:
 
- .Configure `tokenFromMultipartDataEnabled` with `ServerCsrfTokenRequestAttributeHandler`
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
 
- 	ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
 
- 	requestHandler.setTokenFromMultipartDataEnabled(true);
 
- 	http
 
- 		// ...
 
- 		.csrf((csrf) -> csrf
 
- 			.csrfTokenRequestHandler(requestHandler)
 
- 		);
 
- 	return http.build();
 
- }
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
 
- 	val requestHandler = ServerCsrfTokenRequestAttributeHandler()
 
- 	requestHandler.tokenFromMultipartDataEnabled = true
 
- 	return http {
 
- 		// ...
 
- 		csrf {
 
- 			csrfTokenRequestHandler = requestHandler
 
- 		}
 
- 	}
 
- }
 
- ----
 
- ====
 
- === Protect against CSRF BREACH
 
- You can opt into Spring Security 6's default support for BREACH protection of the `CsrfToken` using the following configuration:
 
- .`CsrfToken` BREACH Protection
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
 
- 	XorServerCsrfTokenRequestAttributeHandler requestHandler = new XorServerCsrfTokenRequestAttributeHandler();
 
- 	// ...
 
- 	http
 
- 		// ...
 
- 		.csrf((csrf) -> csrf
 
- 			.csrfTokenRequestHandler(requestHandler)
 
- 		);
 
- 	return http.build();
 
- }
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
 
- 	val requestHandler = XorServerCsrfTokenRequestAttributeHandler()
 
- 	// ...
 
- 	return http {
 
- 		// ...
 
- 		csrf {
 
- 			csrfTokenRequestHandler = requestHandler
 
- 		}
 
- 	}
 
- }
 
- ----
 
- ====
 
- [[reactive-csrf-breach-opt-out]]
 
- === Opt-out Steps
 
- If configuring CSRF BREACH protection gives you trouble, take a look at these scenarios for optimal opt out behavior:
 
- ==== I am using AngularJS or another Javascript framework
 
- If you are using AngularJS and the https://angular.io/api/common/http/HttpClientXsrfModule[HttpClientXsrfModule] (or a similar module in another framework) along with `CookieServerCsrfTokenRepository.withHttpOnlyFalse()`, you may find that automatic support no longer works.
 
- In this case, you can configure Spring Security to validate the raw `CsrfToken` from the cookie while keeping CSRF BREACH protection of the response using a custom `ServerCsrfTokenRequestHandler` with delegation, like so:
 
- .Configure `CsrfToken` BREACH Protection to validate raw tokens
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
 
- 	CookieServerCsrfTokenRepository tokenRepository = CookieServerCsrfTokenRepository.withHttpOnlyFalse();
 
- 	XorServerCsrfTokenRequestAttributeHandler delegate = new XorServerCsrfTokenRequestAttributeHandler();
 
- 	// Use only the handle() method of XorServerCsrfTokenRequestAttributeHandler and the
 
- 	// default implementation of resolveCsrfTokenValue() from ServerCsrfTokenRequestHandler
 
- 	ServerCsrfTokenRequestHandler requestHandler = delegate::handle;
 
- 	http
 
- 		// ...
 
- 		.csrf((csrf) -> csrf
 
- 			.csrfTokenRepository(tokenRepository)
 
- 			.csrfTokenRequestHandler(requestHandler)
 
- 		);
 
- 	return http.build();
 
- }
 
- @Bean
 
- WebFilter csrfCookieWebFilter() {
 
- 	return (exchange, chain) -> {
 
- 		Mono<CsrfToken> csrfToken = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty());
 
- 		return csrfToken.doOnSuccess(token -> {
 
- 			/* Ensures the token is subscribed to. */
 
- 		}).then(chain.filter(exchange));
 
- 	};
 
- }
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
 
- 	val tokenRepository = CookieServerCsrfTokenRepository.withHttpOnlyFalse()
 
- 	val delegate = XorServerCsrfTokenRequestAttributeHandler()
 
- 	// Use only the handle() method of XorServerCsrfTokenRequestAttributeHandler and the
 
- 	// default implementation of resolveCsrfTokenValue() from ServerCsrfTokenRequestHandler
 
- 	val requestHandler = ServerCsrfTokenRequestHandler(delegate::handle)
 
- 	return http.invoke {
 
- 		// ...
 
- 		csrf {
 
- 			csrfTokenRepository = tokenRepository
 
- 			csrfTokenRequestHandler = requestHandler
 
- 		}
 
- 	}
 
- }
 
- @Bean
 
- fun csrfCookieWebFilter(): WebFilter {
 
- 	return WebFilter { exchange, chain ->
 
- 		val csrfToken = exchange.getAttribute<Mono<CsrfToken>>(CsrfToken::class.java.name) ?: Mono.empty()
 
- 		csrfToken.doOnSuccess {
 
-             /* Ensures the token is subscribed to. */
 
- 		}.then(chain.filter(exchange))
 
- 	}
 
- }
 
- ----
 
- ====
 
- ==== I need to opt out of CSRF BREACH protection for another reason
 
- If CSRF BREACH protection does not work for you for another reason, you can opt out using the following configuration:
 
- .Opt out of `CsrfToken` BREACH protection
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
 
- 	ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
 
- 	http
 
- 		// ...
 
- 		.csrf((csrf) -> csrf
 
- 			.csrfTokenRequestHandler(requestHandler)
 
- 		);
 
- 	return http.build();
 
- }
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
 
- 	val requestHandler = ServerCsrfTokenRequestAttributeHandler()
 
- 	return http {
 
- 		// ...
 
- 		csrf {
 
- 			csrfTokenRequestHandler = requestHandler
 
- 		}
 
- 	}
 
- }
 
- ----
 
- ====
 
- == Use `AuthorizationManager` for Method Security
 
- xref:reactive/authorization/method.adoc[Method Security] has been xref:reactive/authorization/method.adoc#jc-enable-reactive-method-security-authorization-manager[improved] through {security-api-url}org/springframework/security/authorization/AuthorizationManager.html[the `AuthorizationManager` API] and direct use of Spring AOP.
 
- Should you run into trouble with making these changes, you can follow the
 
- <<reactive-authorizationmanager-methods-opt-out,opt out steps>> at the end of this section.
 
- In Spring Security 5.8, `useAuthorizationManager` was added to {security-api-url}org/springframework/security/config/annotation/method/configuration/EnableReactiveMethodSecurity.html[`@EnableReactiveMethodSecurity`] to allow applications to opt in to ``AuthorizationManager``'s features.
 
- [[reactive-change-to-useauthorizationmanager]]
 
- === Change `useAuthorizationManager` to `true`
 
- To opt in, change `useAuthorizationManager` to `true` like so:
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @EnableReactiveMethodSecurity
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @EnableReactiveMethodSecurity
 
- ----
 
- ====
 
- changes to:
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @EnableReactiveMethodSecurity(useAuthorizationManager = true)
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @EnableReactiveMethodSecurity(useAuthorizationManager = true)
 
- ----
 
- ====
 
- [[reactive-check-for-annotationconfigurationexceptions]]
 
- === Check for ``AnnotationConfigurationException``s
 
- `useAuthorizationManager` activates stricter enforcement of Spring Security's non-repeatable or otherwise incompatible annotations.
 
- If after turning on `useAuthorizationManager` you see ``AnnotationConfigurationException``s in your logs, follow the instructions in the exception message to clean up your application's method security annotation usage.
 
- [[reactive-authorizationmanager-methods-opt-out]]
 
- === Opt-out Steps
 
- If you ran into trouble with `AuthorizationManager` for reactive method security, you can opt out by changing:
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @EnableReactiveMethodSecurity
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @EnableReactiveMethodSecurity
 
- ----
 
- ====
 
- to:
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @EnableReactiveMethodSecurity(useAuthorizationManager = false)
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @EnableReactiveMethodSecurity(useAuthorizationManager = false)
 
- ----
 
- ====
 
- == Propagate ``AuthenticationServiceException``s
 
- {security-api-url}org/springframework/security/web/server/Webauthentication/AuthenticationWebFilter.html[`AuthenticationFilter`] propagates {security-api-url}org/springframework/security/authentication/AuthenticationServiceException.html[``AuthenticationServiceException``]s to the {security-api-url}org/springframework/security/web/server/ServerAuthenticationEntryPoint.html[`ServerAuthenticationEntryPoint`].
 
- Because ``AuthenticationServiceException``s  represent a server-side error instead of a client-side error, in 6.0, this changes to propagate them to the container.
 
- === Configure `ServerAuthenticationFailureHandler` to rethrow ``AuthenticationServiceException``s
 
- To prepare for the 6.0 default, `httpBasic` and `oauth2ResourceServer` should be configured to rethrow ``AuthenticationServiceException``s.
 
- For each, construct the appropriate authentication entry point for `httpBasic` and for `oauth2ResourceServer`:
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- ServerAuthenticationEntryPoint bearerEntryPoint = new BearerTokenServerAuthenticationEntryPoint();
 
- ServerAuthenticationEntryPoint basicEntryPoint = new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED);
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- val bearerEntryPoint: ServerAuthenticationEntryPoint = BearerTokenServerAuthenticationEntryPoint()
 
- val basicEntryPoint: ServerAuthenticationEntryPoint = HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)
 
- ----
 
- ====
 
- [NOTE]
 
- ====
 
- If you use a custom `AuthenticationEntryPoint` for either or both mechanisms, use that one instead for the remaining steps.
 
- ====
 
- Then, construct and configure a `ServerAuthenticationEntryPointFailureHandler` for each one:
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- AuthenticationFailureHandler bearerFailureHandler = new ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint);
 
- bearerFailureHandler.setRethrowAuthenticationServiceException(true);
 
- AuthenticationFailureHandler basicFailureHandler = new ServerAuthenticationEntryPointFailureHandler(basicEntryPoint);
 
- basicFailureHandler.setRethrowAuthenticationServiceException(true)
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- val bearerFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint)
 
- bearerFailureHandler.setRethrowAuthenticationServiceException(true)
 
- val basicFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(basicEntryPoint)
 
- basicFailureHandler.setRethrowAuthenticationServiceException(true)
 
- ----
 
- ====
 
- Finally, wire each authentication failure handler into the DSL, like so:
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- http
 
-     .httpBasic((basic) -> basic.authenticationFailureHandler(basicFailureHandler))
 
-     .oauth2ResourceServer((oauth2) -> oauth2.authenticationFailureHandler(bearerFailureHandler))
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- http {
 
-     httpBasic {
 
-         authenticationFailureHandler = basicFailureHandler
 
-     }
 
-     oauth2ResourceServer {
 
-         authenticationFailureHandler = bearerFailureHandler
 
-     }
 
- }
 
- ----
 
- ====
 
- [[reactive-authenticationfailurehandler-opt-out]]
 
- === Opt-out Steps
 
- To opt-out of the 6.0 defaults and instead continue to pass `AuthenticationServiceException` on to ``ServerAuthenticationEntryPoint``s, you can follow the same steps as above, except set `rethrowAuthenticationServiceException` to false.
 
- == Address OAuth2 Client Deprecations
 
- === `ServerOAuth2AuthorizedClientExchangeFilterFunction`
 
- The method `setAccessTokenExpiresSkew(...)` can be replaced with one of:
 
- * `ClientCredentialsReactiveOAuth2AuthorizedClientProvider#setClockSkew(...)`
 
- * `RefreshTokenReactiveOAuth2AuthorizedClientProvider#setClockSkew(...)`
 
- * `JwtBearerReactiveOAuth2AuthorizedClientProvider#setClockSkew(...)`
 
- The method `setClientCredentialsTokenResponseClient(...)` can be replaced with the constructor `ServerOAuth2AuthorizedClientExchangeFilterFunction(ReactiveOAuth2AuthorizedClientManager)`.
 
- [NOTE]
 
- ====
 
- See xref:reactive/oauth2/client/authorization-grants.adoc#oauth2Client-client-creds-grant[Client Credentials] for more information.
 
- ====
 
- === `WebSessionOAuth2ServerAuthorizationRequestRepository`
 
- The method `setAllowMultipleAuthorizationRequests(...)` has no direct replacement.
 
- === `UnAuthenticatedServerOAuth2AuthorizedClientRepository`
 
- The class `UnAuthenticatedServerOAuth2AuthorizedClientRepository` has no direct replacement. Usage of the class can be replaced with `AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager`.
 
 
  |