= 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: HttpSecurity): 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: HttpSecurity): 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: HttpSecurity): SecurityWebFilterChain { val requestHandler = XorServerCsrfTokenRequestAttributeHandler() // ... 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 <> 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`.