whats-new.adoc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. [[new]]
  2. = What's New in Spring Security 6.3
  3. Spring Security 6.3 provides a number of new features.
  4. Below are the highlights of the release, or you can view https://github.com/spring-projects/spring-security/releases[the release notes] for a detailed listing of each feature and bug fix.
  5. == Passive JDK Serialization Support
  6. When it comes to its support for JDK-serialized security components, Spring Security has historically been quite aggressive, supporting each serialization version for only one Spring Security minor version.
  7. This meant that if you had JDK-serialized security components, then they would need to be evacuated before upgrading to the next Spring Security version since they would no longer be deserializable.
  8. Now that Spring Security performs a minor release every six months, this became a much larger pain point.
  9. To address that, Spring Security now will https://spring.io/blog/2024/01/19/spring-security-6-3-adds-passive-jdk-serialization-deserialization-for[maintain passivity with JDK serialization], like it does with JSON serialization, making for more seamless upgrades.
  10. == Authorization
  11. An ongoing theme for the last several releases has been to refactor and improve Spring Security's authorization subsystem.
  12. Starting with replacing the `AccessDecisionManager` API with `AuthorizationManager` it's now come to the point where we are able to add several exciting new features.
  13. === Annotation Parameters - https://github.com/spring-projects/spring-security/issues/14480[#14480]
  14. The first 6.3 feature is https://github.com/spring-projects/spring-security/issues/14480[support for annotation parameters].
  15. Consider Spring Security's support for xref:servlet/authorization/method-security.adoc#meta-annotations[meta-annotations] like this one:
  16. [tabs]
  17. ======
  18. Java::
  19. +
  20. [source,java,role="primary"]
  21. ----
  22. @Retention(RetentionPolicy.RUNTIME)
  23. @Target(ElementType.METHOD)
  24. @PreAuthorize("hasAuthority('SCOPE_message:read')")
  25. public @interface HasMessageRead {}
  26. ----
  27. Kotlin::
  28. +
  29. .Kotlin
  30. [source,kotlin,role="secondary"]
  31. ----
  32. @Retention(RetentionPolicy.RUNTIME)
  33. @Target(ElementType.METHOD)
  34. @PreAuthorize("hasAuthority('SCOPE_message:read')")
  35. annotation class HasMessageRead
  36. ----
  37. ======
  38. Before this release, something like this is only helpful when it is used widely across the codebase.
  39. But now, xref:servlet/authorization/method-security.adoc#_templating_meta_annotation_expressions[you can add parameters] like so:
  40. [tabs]
  41. ======
  42. Java::
  43. +
  44. [source,java,role="primary"]
  45. ----
  46. @Retention(RetentionPolicy.RUNTIME)
  47. @Target(ElementType.METHOD)
  48. @PreAuthorize("hasAuthority('SCOPE_{scope}')")
  49. public @interface HasScope {
  50. String scope();
  51. }
  52. ----
  53. Kotlin::
  54. +
  55. [source,kotlin,role="secondary"]
  56. ----
  57. @Retention(RetentionPolicy.RUNTIME)
  58. @Target(ElementType.METHOD)
  59. @PreAuthorize("hasAuthority('SCOPE_{scope}')")
  60. annotation class HasScope (val scope:String)
  61. ----
  62. ======
  63. making it possible to do things like this:
  64. [tabs]
  65. ======
  66. Java::
  67. +
  68. [source,java,role="primary"]
  69. ----
  70. @HasScope("message:read")
  71. public String method() { ... }
  72. ----
  73. Kotlin::
  74. +
  75. [source,kotlin,role="secondary"]
  76. ----
  77. @HasScope("message:read")
  78. fun method(): String { ... }
  79. ----
  80. ======
  81. and apply your SpEL expression in several more places.
  82. === Secure Return Values - https://github.com/spring-projects/spring-security/issues/14596[#14596], https://github.com/spring-projects/spring-security/issues/14597[#14597]
  83. Since the early days of Spring Security, you've been able to xref:servlet/authorization/method-security.adoc#use-preauthorize[annotate Spring beans with `@PreAuthorize` and `@PostAuthorize`].
  84. But controllers, services, and repositories are not the only things you care to secure.
  85. For example, what about a domain object `Order` where only admins should be able to call the `Order#getPayment` method?
  86. Now in 6.3, https://github.com/spring-projects/spring-security/issues/14597[you can annotate those methods], too.
  87. First, annotate the `getPayment` method like you would a Spring bean:
  88. [tabs]
  89. ======
  90. Java::
  91. +
  92. [source,java,role="primary"]
  93. ----
  94. public class Order {
  95. @HasScope("payment:read")
  96. Payment getPayment() { ... }
  97. }
  98. ----
  99. Kotlin::
  100. +
  101. [source,kotlin,role="secondary"]
  102. ----
  103. class Order {
  104. @HasScope("payment:read")
  105. fun getPayment(): Payment { ... }
  106. }
  107. ----
  108. ======
  109. And then xref:servlet/authorization/method-security.adoc#authorize-object[annotate your Spring Data repository with `@AuthorizeReturnObject`] like so:
  110. [tabs]
  111. ======
  112. Java::
  113. +
  114. [source,java,role="primary"]
  115. ----
  116. public interface OrderRepository implements CrudRepository<Order, String> {
  117. @AuthorizeReturnObject
  118. Optional<Order> findOrderById(String id);
  119. }
  120. ----
  121. Kotlin::
  122. +
  123. [source,kotlin,role="secondary"]
  124. ----
  125. interface OrderRepository : CrudRepository<Order, String> {
  126. @AuthorizeReturnObject
  127. fun findOrderById(id: String?): Optional<Order?>?
  128. }
  129. ----
  130. ======
  131. At that point, Spring Security will protect any `Order` returned from `findOrderById` by way of https://github.com/spring-projects/spring-security/issues/14596[proxying the `Order` instance].
  132. === Error Handling - https://github.com/spring-projects/spring-security/issues/14598[#14598], https://github.com/spring-projects/spring-security/issues/14600[#14600], https://github.com/spring-projects/spring-security/issues/14601[#14601]
  133. In this release, you can also https://github.com/spring-projects/spring-security/issues/14601[intercept and handle failure at the method level] with its last new method security annotation.
  134. When you xref:servlet/authorization/method-security.adoc#fallback-values-authorization-denied[annotate a method with `@HandleAuthorizationDenied`] like so:
  135. [tabs]
  136. ======
  137. Java::
  138. +
  139. [source,java,role="primary"]
  140. ----
  141. public class Payment {
  142. @HandleAuthorizationDenied(handlerClass=Mask.class)
  143. @PreAuthorize("hasAuthority('card:read')")
  144. public String getCreditCardNumber() { ... }
  145. }
  146. ----
  147. Kotlin::
  148. +
  149. [source,kotlin,role="secondary"]
  150. ----
  151. class Payment {
  152. @HandleAuthorizationDenied(handlerClass=Mask.class)
  153. @PreAuthorize("hasAuthority('card:read')")
  154. fun getCreditCardNumber(): String { ... }
  155. }
  156. ----
  157. ======
  158. and publish a `Mask` bean:
  159. [tabs]
  160. ======
  161. Java::
  162. +
  163. [source,java,role="primary"]
  164. ----
  165. @Component
  166. public class Mask implements MethodAuthorizationDeniedHandler {
  167. @Override
  168. public Object handleDeniedInvocation(MethodInvocation invocation, AuthorizationResult result) {
  169. return "***";
  170. }
  171. }
  172. ----
  173. Kotlin::
  174. +
  175. [source,kotlin,role="secondary"]
  176. ----
  177. @Component
  178. class Mask : MethodAuthorizationDeniedHandler {
  179. fun handleDeniedInvocation(invocation: MethodInvocation?, result: AuthorizationResult?): Any = "***"
  180. }
  181. ----
  182. ======
  183. then any unauthorized call to `Payment#getCreditCardNumber` will return `\***` instead of the number.
  184. You can see all these features at work together in https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/data[the latest Spring Security Data sample].
  185. == Compromised Password Checking - https://github.com/spring-projects/spring-security/issues/7395[#7395]
  186. If you are going to let users pick passwords, it's critical to ensure that such a password isn't already compromised.
  187. Spring Security 6.3 makes this as simple as xref:features/authentication/password-storage.adoc#authentication-compromised-password-check[publishing a `CompromisedPasswordChecker` bean]:
  188. [tabs]
  189. ======
  190. Java::
  191. +
  192. [source,java,role="primary"]
  193. ----
  194. @Bean
  195. public CompromisedPasswordChecker compromisedPasswordChecker() {
  196. return new HaveIBeenPwnedRestApiPasswordChecker();
  197. }
  198. ----
  199. Kotlin::
  200. +
  201. [source,kotlin,role="secondary"]
  202. ----
  203. @Bean
  204. fun compromisedPasswordChecker(): CompromisedPasswordChecker = HaveIBeenPwnedRestApiPasswordChecker()
  205. ----
  206. ======
  207. == `spring-security-rsa` is now part of Spring Security - https://github.com/spring-projects/spring-security/issues/14202[#14202]
  208. Since 2017, Spring Security has been undergoing a long-standing initiative to fold various Spring Security extensions into Spring Security proper.
  209. In 6.3, `spring-security-rsa` becomes the latest of these projects which will help the team maintain and add features to it, long-term.
  210. `spring-security-rsa` provides a number of https://github.com/spring-projects/spring-security/blob/main/crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaSecretEncryptor.java[handy `BytesEncryptor`] https://github.com/spring-projects/spring-security/blob/main/crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaRawEncryptor.java[implementations] as well as https://github.com/spring-projects/spring-security/blob/main/crypto/src/main/java/org/springframework/security/crypto/encrypt/KeyStoreKeyFactory.java[a simpler API for working with ``KeyStore``s].
  211. == OAuth 2.0 Token Exchange Grant - https://github.com/spring-projects/spring-security/issues/5199[#5199]
  212. One of https://github.com/spring-projects/spring-security/issues/5199[the most highly-voted OAuth 2.0 features] in Spring Security is now in place in 6.3, which is the support for https://datatracker.ietf.org/doc/html/rfc8693#section-2[the OAuth 2.0 Token Exchange grant].
  213. For xref:servlet/oauth2/client/authorization-grants.adoc#token-exchange-grant-access-token[any client configured for token exchange], you can activate it in Spring Security by adding a `TokenExchangeAuthorizedClientProvider` instance to your `OAuth2AuthorizedClientManager` like so:
  214. [tabs]
  215. ======
  216. Java::
  217. +
  218. [source,java,role="primary"]
  219. ----
  220. @Bean
  221. public OAuth2AuthorizedClientProvider tokenExchange() {
  222. return new TokenExchangeOAuth2AuthorizedClientProvider();
  223. }
  224. ----
  225. Kotlin::
  226. +
  227. [source,kotlin,role="secondary"]
  228. ----
  229. @Bean
  230. fun tokenExchange(): OAuth2AuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
  231. ----
  232. ======
  233. and then xref:servlet/oauth2/client/authorized-clients.adoc#oauth2Client-registered-authorized-client[use the `@RegisteredOAuth2AuthorizedClient` annotation] as per usual to retrieve the appropriate token with the expanded privileges your resource server needs.
  234. == Additional Highlights
  235. - https://github.com/spring-projects/spring-security/pull/14655[gh-14655] - Add `DelegatingAuthenticationConverter
  236. - Add Concurrent Sessions Control on WebFlux - https://github.com/spring-projects/spring-security/issues/6192[gh-6192] - xref:reactive/authentication/concurrent-sessions-control.adoc[(docs)]
  237. - https://github.com/spring-projects/spring-security/pull/14193[gh-14193] - Added support for CAS Gateway Authentication
  238. - https://github.com/spring-projects/spring-security/issues/13259[gh-13259] - Customize when UserInfo is called
  239. - https://github.com/spring-projects/spring-security/pull/14168[gh-14168] - Introduce Customizable AuthorizationFailureHandler in OAuth2AuthorizationRequestRedirectFilter
  240. - https://github.com/spring-projects/spring-security/issues/14672[gh-14672] - Customize mapping the OidcUser from OidcUserRequest and OidcUserInfo
  241. - https://github.com/spring-projects/spring-security/issues/10538[gh-10538] - Support Certificate-Bound JWT Access Token Validation
  242. - https://github.com/spring-projects/spring-security/pull/14265[gh-14265] - Support Nexted username in UserInfo response
  243. - https://github.com/spring-projects/spring-security/pull/14265[gh-14449] - Add `SecurityContext` argument resolver
  244. And for an exhaustive list, please see the release notes for https://github.com/spring-projects/spring-security/releases/tag/6.3.0-RC1[6.3.0-RC1], https://github.com/spring-projects/spring-security/releases/tag/6.3.0-M3[6.3.0-M3], https://github.com/spring-projects/spring-security/releases/tag/6.3.0-M2[6.3.0-M2], and https://github.com/spring-projects/spring-security/releases/tag/6.3.0-M1[6.3.0-M1].
  245. `