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.
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.
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.
Now that Spring Security performs a minor release every six months, this became a much larger pain point.
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.
An ongoing theme for the last several releases has been to refactor and improve Spring Security's authorization subsystem.
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.
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`].
But controllers, services, and repositories are not the only things you care to secure.
For example, what about a domain object `Order` where only admins should be able to call the `Order#getPayment` method?
Now in 6.3, https://github.com/spring-projects/spring-security/issues/14597[you can annotate those methods], too.
First, annotate the `getPayment` method like you would a Spring bean:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
public class Order {
@HasScope("payment:read")
Payment getPayment() { ... }
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
class Order {
@HasScope("payment:read")
fun getPayment(): Payment { ... }
}
----
======
And then xref:servlet/authorization/method-security.adoc#authorize-object[annotate your Spring Data repository with `@AuthorizeReturnObject`] like so:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
public interface OrderRepository implements CrudRepository<Order, String> {
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].
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.
When you xref:servlet/authorization/method-security.adoc#fallback-values-authorization-denied[annotate a method with `@HandleAuthorizationDenied`] like so:
public class Mask implements MethodAuthorizationDeniedHandler {
@Override
public Object handleDeniedInvocation(MethodInvocation invocation, AuthorizationResult result) {
return "***";
}
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Component
class Mask : MethodAuthorizationDeniedHandler {
fun handleDeniedInvocation(invocation: MethodInvocation?, result: AuthorizationResult?): Any = "***"
}
----
======
then any unauthorized call to `Payment#getCreditCardNumber` will return `\***` instead of the number.
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].
If you are going to let users pick passwords, it's critical to ensure that such a password isn't already compromised.
Spring Security 6.3 makes this as simple as xref:features/authentication/password-storage.adoc#authentication-compromised-password-check[publishing a `CompromisedPasswordChecker` bean]:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
public CompromisedPasswordChecker compromisedPasswordChecker() {
return new HaveIBeenPwnedRestApiPasswordChecker();
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun compromisedPasswordChecker(): CompromisedPasswordChecker = HaveIBeenPwnedRestApiPasswordChecker()
----
======
== `spring-security-rsa` is now part of Spring Security - https://github.com/spring-projects/spring-security/issues/14202[#14202]
Since 2017, Spring Security has been undergoing a long-standing initiative to fold various Spring Security extensions into Spring Security proper.
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.
`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].
== OAuth 2.0 Token Exchange Grant - https://github.com/spring-projects/spring-security/issues/5199[#5199]
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].
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:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
public OAuth2AuthorizedClientProvider tokenExchange() {
return new TokenExchangeOAuth2AuthorizedClientProvider();
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun tokenExchange(): OAuth2AuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
----
======
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.
- https://github.com/spring-projects/spring-security/issues/6192[gh-6192] - Add Concurrent Sessions Control on WebFlux (xref:reactive/authentication/concurrent-sessions-control.adoc[docs])
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].