| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574 | = Reactive MigrationsIf 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 MigrationsThe 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[tabs]======Java::+[source,java,role="primary"]----@BeanSecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {	http		// ...		.csrf((csrf) -> csrf			.tokenFromMultipartDataEnabled(true)		);	return http.build();}----Kotlin::+[source,kotlin,role="secondary"]----@Beanopen fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {	return http {		// ...		csrf {			tokenFromMultipartDataEnabled = true		}	}}----======can be replaced with:.Configure `tokenFromMultipartDataEnabled` with `ServerCsrfTokenRequestAttributeHandler`[tabs]======Java::+[source,java,role="primary"]----@BeanSecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {	ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();	requestHandler.setTokenFromMultipartDataEnabled(true);	http		// ...		.csrf((csrf) -> csrf			.csrfTokenRequestHandler(requestHandler)		);	return http.build();}----Kotlin::+[source,kotlin,role="secondary"]----@Beanopen fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {	val requestHandler = ServerCsrfTokenRequestAttributeHandler()	requestHandler.tokenFromMultipartDataEnabled = true	return http {		// ...		csrf {			csrfTokenRequestHandler = requestHandler		}	}}----========= Protect against CSRF BREACHYou can opt into Spring Security 6's default support for BREACH protection of the `CsrfToken` using the following configuration:.`CsrfToken` BREACH Protection[tabs]======Java::+[source,java,role="primary"]----@BeanSecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {	XorServerCsrfTokenRequestAttributeHandler requestHandler = new XorServerCsrfTokenRequestAttributeHandler();	// ...	http		// ...		.csrf((csrf) -> csrf			.csrfTokenRequestHandler(requestHandler)		);	return http.build();}----Kotlin::+[source,kotlin,role="secondary"]----@Beanopen fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {	val requestHandler = XorServerCsrfTokenRequestAttributeHandler()	// ...	return http {		// ...		csrf {			csrfTokenRequestHandler = requestHandler		}	}}----======[[reactive-csrf-breach-opt-out]]=== Opt-out StepsIf 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 frameworkIf 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[tabs]======Java::+[source,java,role="primary"]----@BeanSecurityWebFilterChain 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();}@BeanWebFilter 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"]----@Beanopen 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		}	}}@Beanfun 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 reasonIf 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[tabs]======Java::+[source,java,role="primary"]----@BeanSecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {	ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();	http		// ...		.csrf((csrf) -> csrf			.csrfTokenRequestHandler(requestHandler)		);	return http.build();}----Kotlin::+[source,kotlin,role="secondary"]----@Beanopen fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {	val requestHandler = ServerCsrfTokenRequestAttributeHandler()	return http {		// ...		csrf {			csrfTokenRequestHandler = requestHandler		}	}}----======== Use `AuthorizationManager` for Method Securityxref: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:[tabs]======Java::+[source,java,role="primary"]----@EnableReactiveMethodSecurity----Kotlin::+[source,kotlin,role="secondary"]----@EnableReactiveMethodSecurity----======changes to:[tabs]======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 StepsIf you ran into trouble with `AuthorizationManager` for reactive method security, you can opt out by changing:[tabs]======Java::+[source,java,role="primary"]----@EnableReactiveMethodSecurity----Kotlin::+[source,kotlin,role="secondary"]----@EnableReactiveMethodSecurity----======to:[tabs]======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``sTo 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`:[tabs]======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:[tabs]======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:[tabs]======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 StepsTo 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.[[add-configuration-annotation]]== Add `@Configuration` annotationIn 6.0, `@Configuration` is removed from `@EnableWebFluxSecurity` and `@EnableReactiveMethodSecurity`.To prepare for this, wherever you are using one of these annotations, you may need to add `@Configuration`.For example, `@EnableReactiveMethodSecurity` changes from:[tabs]======Java::+[source,java,role="primary"]----@EnableReactiveMethodSecuritypublic class MyConfiguration {	// ...}----======[tabs]======Kotlin::+[source,java,role="primary"]----@EnableReactiveMethodSecurityopen class MyConfiguration {	// ...}----======to:[tabs]======Java::+[source,java,role="primary"]----@Configuration@EnableReactiveMethodSecuritypublic class MyConfiguration {	// ...}----======[tabs]======Kotlin::+[source,java,role="primary"]----@Configuration@EnableReactiveMethodSecurityopen class MyConfiguration {	// ...}----======== 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`.== Add `@Configuration` to `@Enable*` annotationsIn 6.0, all Spring Security's `@Enable*` annotations had their `@Configuration` removed.While convenient, it was not consistent with the rest of the Spring projects and most notably Spring Framework's `@Enable*` annotations.Additionally, the introduction of support for `@Configuration(proxyBeanMethods=false)` in Spring Framework provides another reason to remove `@Configuration` meta-annotation from Spring Security's `@Enable*` annotations and allow users to opt into their preferred configuration mode.The following annotations had their `@Configuration` removed:- `@EnableGlobalAuthentication`- `@EnableGlobalMethodSecurity`- `@EnableMethodSecurity`- `@EnableReactiveMethodSecurity`- `@EnableWebSecurity`- `@EnableWebFluxSecurity`For example, if you are using `@EnableWebFluxSecurity`, you will need to change:[tabs]======Java::+[source,java,role="primary"]----@EnableWebFluxSecuritypublic class SecurityConfig {	// ...}----======to:[tabs]======Java::+[source,java,role="primary"]----@Configuration@EnableWebFluxSecuritypublic class SecurityConfig {	// ...}----======And the same applies to every other annotation listed above.
 |