reactive.adoc 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. = Reactive Migrations
  2. 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.
  3. == Exploit Protection Migrations
  4. The following steps relate to changes around how to configure CSRF.
  5. === Configure `tokenFromMultipartDataEnabled`
  6. In Spring Security 5.8, the method `tokenFromMultipartDataEnabled` was deprecated in favor of `ServerCsrfTokenRequestAttributeHandler#setTokenFromMultipartDataEnabled`.
  7. To address the deprecation, the following code:
  8. .Configure `tokenFromMultipartDataEnabled` with DSL
  9. ====
  10. .Java
  11. [source,java,role="primary"]
  12. ----
  13. @Bean
  14. SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
  15. http
  16. // ...
  17. .csrf((csrf) -> csrf
  18. .tokenFromMultipartDataEnabled(true)
  19. );
  20. return http.build();
  21. }
  22. ----
  23. .Kotlin
  24. [source,kotlin,role="secondary"]
  25. ----
  26. @Bean
  27. open fun securityWebFilterChain(http: HttpSecurity): SecurityWebFilterChain {
  28. return http {
  29. // ...
  30. csrf {
  31. tokenFromMultipartDataEnabled = true
  32. }
  33. }
  34. }
  35. ----
  36. ====
  37. can be replaced with:
  38. .Configure `tokenFromMultipartDataEnabled` with `ServerCsrfTokenRequestAttributeHandler`
  39. ====
  40. .Java
  41. [source,java,role="primary"]
  42. ----
  43. @Bean
  44. SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
  45. ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
  46. requestHandler.setTokenFromMultipartDataEnabled(true);
  47. http
  48. // ...
  49. .csrf((csrf) -> csrf
  50. .csrfTokenRequestHandler(requestHandler)
  51. );
  52. return http.build();
  53. }
  54. ----
  55. .Kotlin
  56. [source,kotlin,role="secondary"]
  57. ----
  58. @Bean
  59. open fun securityWebFilterChain(http: HttpSecurity): SecurityWebFilterChain {
  60. val requestHandler = ServerCsrfTokenRequestAttributeHandler()
  61. requestHandler.tokenFromMultipartDataEnabled = true
  62. return http {
  63. // ...
  64. csrf {
  65. csrfTokenRequestHandler = requestHandler
  66. }
  67. }
  68. }
  69. ----
  70. ====
  71. === Protect against CSRF BREACH
  72. You can opt into Spring Security 6's default support for BREACH protection of the `CsrfToken` using the following configuration:
  73. .`CsrfToken` BREACH Protection
  74. ====
  75. .Java
  76. [source,java,role="primary"]
  77. ----
  78. @Bean
  79. SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
  80. XorServerCsrfTokenRequestAttributeHandler requestHandler = new XorServerCsrfTokenRequestAttributeHandler();
  81. // ...
  82. http
  83. // ...
  84. .csrf((csrf) -> csrf
  85. .csrfTokenRequestHandler(requestHandler)
  86. );
  87. return http.build();
  88. }
  89. ----
  90. .Kotlin
  91. [source,kotlin,role="secondary"]
  92. ----
  93. @Bean
  94. open fun securityWebFilterChain(http: HttpSecurity): SecurityWebFilterChain {
  95. val requestHandler = XorServerCsrfTokenRequestAttributeHandler()
  96. // ...
  97. return http {
  98. // ...
  99. csrf {
  100. csrfTokenRequestHandler = requestHandler
  101. }
  102. }
  103. }
  104. ----
  105. ====
  106. == Use `AuthorizationManager` for Method Security
  107. 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.
  108. Should you run into trouble with making these changes, you can follow the
  109. <<reactive-authorizationmanager-methods-opt-out,opt out steps>> at the end of this section.
  110. 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.
  111. [[reactive-change-to-useauthorizationmanager]]
  112. === Change `useAuthorizationManager` to `true`
  113. To opt in, change `useAuthorizationManager` to `true` like so:
  114. ====
  115. .Java
  116. [source,java,role="primary"]
  117. ----
  118. @EnableReactiveMethodSecurity
  119. ----
  120. .Kotlin
  121. [source,kotlin,role="secondary"]
  122. ----
  123. @EnableReactiveMethodSecurity
  124. ----
  125. ====
  126. changes to:
  127. ====
  128. .Java
  129. [source,java,role="primary"]
  130. ----
  131. @EnableReactiveMethodSecurity(useAuthorizationManager = true)
  132. ----
  133. .Kotlin
  134. [source,kotlin,role="secondary"]
  135. ----
  136. @EnableReactiveMethodSecurity(useAuthorizationManager = true)
  137. ----
  138. ====
  139. [[reactive-check-for-annotationconfigurationexceptions]]
  140. === Check for ``AnnotationConfigurationException``s
  141. `useAuthorizationManager` activates stricter enforcement of Spring Security's non-repeatable or otherwise incompatible annotations.
  142. 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.
  143. [[reactive-authorizationmanager-methods-opt-out]]
  144. === Opt-out Steps
  145. If you ran into trouble with `AuthorizationManager` for reactive method security, you can opt out by changing:
  146. ====
  147. .Java
  148. [source,java,role="primary"]
  149. ----
  150. @EnableReactiveMethodSecurity
  151. ----
  152. .Kotlin
  153. [source,kotlin,role="secondary"]
  154. ----
  155. @EnableReactiveMethodSecurity
  156. ----
  157. ====
  158. to:
  159. ====
  160. .Java
  161. [source,java,role="primary"]
  162. ----
  163. @EnableReactiveMethodSecurity(useAuthorizationManager = false)
  164. ----
  165. .Kotlin
  166. [source,kotlin,role="secondary"]
  167. ----
  168. @EnableReactiveMethodSecurity(useAuthorizationManager = false)
  169. ----
  170. ====
  171. == Propagate ``AuthenticationServiceException``s
  172. {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`].
  173. 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.
  174. === Configure `ServerAuthenticationFailureHandler` to rethrow ``AuthenticationServiceException``s
  175. To prepare for the 6.0 default, `httpBasic` and `oauth2ResourceServer` should be configured to rethrow ``AuthenticationServiceException``s.
  176. For each, construct the appropriate authentication entry point for `httpBasic` and for `oauth2ResourceServer`:
  177. ====
  178. .Java
  179. [source,java,role="primary"]
  180. ----
  181. ServerAuthenticationEntryPoint bearerEntryPoint = new BearerTokenServerAuthenticationEntryPoint();
  182. ServerAuthenticationEntryPoint basicEntryPoint = new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED);
  183. ----
  184. .Kotlin
  185. [source,kotlin,role="secondary"]
  186. ----
  187. val bearerEntryPoint: ServerAuthenticationEntryPoint = BearerTokenServerAuthenticationEntryPoint()
  188. val basicEntryPoint: ServerAuthenticationEntryPoint = HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)
  189. ----
  190. ====
  191. [NOTE]
  192. ====
  193. If you use a custom `AuthenticationEntryPoint` for either or both mechanisms, use that one instead for the remaining steps.
  194. ====
  195. Then, construct and configure a `ServerAuthenticationEntryPointFailureHandler` for each one:
  196. ====
  197. .Java
  198. [source,java,role="primary"]
  199. ----
  200. AuthenticationFailureHandler bearerFailureHandler = new ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint);
  201. bearerFailureHandler.setRethrowAuthenticationServiceException(true);
  202. AuthenticationFailureHandler basicFailureHandler = new ServerAuthenticationEntryPointFailureHandler(basicEntryPoint);
  203. basicFailureHandler.setRethrowAuthenticationServiceException(true)
  204. ----
  205. .Kotlin
  206. [source,kotlin,role="secondary"]
  207. ----
  208. val bearerFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint)
  209. bearerFailureHandler.setRethrowAuthenticationServiceException(true)
  210. val basicFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(basicEntryPoint)
  211. basicFailureHandler.setRethrowAuthenticationServiceException(true)
  212. ----
  213. ====
  214. Finally, wire each authentication failure handler into the DSL, like so:
  215. ====
  216. .Java
  217. [source,java,role="primary"]
  218. ----
  219. http
  220. .httpBasic((basic) -> basic.authenticationFailureHandler(basicFailureHandler))
  221. .oauth2ResourceServer((oauth2) -> oauth2.authenticationFailureHandler(bearerFailureHandler))
  222. ----
  223. .Kotlin
  224. [source,kotlin,role="secondary"]
  225. ----
  226. http {
  227. httpBasic {
  228. authenticationFailureHandler = basicFailureHandler
  229. }
  230. oauth2ResourceServer {
  231. authenticationFailureHandler = bearerFailureHandler
  232. }
  233. }
  234. ----
  235. ====
  236. [[reactive-authenticationfailurehandler-opt-out]]
  237. === Opt-out Steps
  238. 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.
  239. == Address OAuth2 Client Deprecations
  240. === `ServerOAuth2AuthorizedClientExchangeFilterFunction`
  241. The method `setAccessTokenExpiresSkew(...)` can be replaced with one of:
  242. * `ClientCredentialsReactiveOAuth2AuthorizedClientProvider#setClockSkew(...)`
  243. * `RefreshTokenReactiveOAuth2AuthorizedClientProvider#setClockSkew(...)`
  244. * `JwtBearerReactiveOAuth2AuthorizedClientProvider#setClockSkew(...)`
  245. The method `setClientCredentialsTokenResponseClient(...)` can be replaced with the constructor `ServerOAuth2AuthorizedClientExchangeFilterFunction(ReactiveOAuth2AuthorizedClientManager)`.
  246. [NOTE]
  247. ====
  248. See xref:reactive/oauth2/client/authorization-grants.adoc#oauth2Client-client-creds-grant[Client Credentials] for more information.
  249. ====
  250. === `WebSessionOAuth2ServerAuthorizationRequestRepository`
  251. The method `setAllowMultipleAuthorizationRequests(...)` has no direct replacement.
  252. === `UnAuthenticatedServerOAuth2AuthorizedClientRepository`
  253. The class `UnAuthenticatedServerOAuth2AuthorizedClientRepository` has no direct replacement. Usage of the class can be replaced with `AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager`.