You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
394 lines
16 KiB
394 lines
16 KiB
[[new]] |
|
= What's New in Spring Security 6.4 |
|
|
|
Spring Security 6.4 provides a number of new features. |
|
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. |
|
|
|
== Deprecation Notices |
|
|
|
As we get closer to Spring Security 7, it's important to stay up to date on deprecations. |
|
As such, this section points out deprecations in the 6.4 release. |
|
|
|
* *Method Security* - `AuthorizationManager#check` is deprecated in favor of `AuthorizationManager#authorize`. |
|
This is primarily to allow the return type to be an interface instead of a concrete class. |
|
If you are invoking `AuthorizationManager#check`, please invoke `AuthorizationManager#authorize` instead. |
|
+ |
|
Relatedly, `AuthorizationEventPublisher#publishEvent` that takes an `AuthorizationDecision` is deprecated in favor of a method of the same name that takes an `AuthorizationResult` interface instead. |
|
* *Method Security* - `PrePostTemplateDefaults` is deprecated in favor of the more generic `AnnotationTemplateExpressionDefaults` as there is now meta-annotation property support for `@AuthenticationPrincipal` and `@CurrentSecurityContext` as well. |
|
If you are constructing a `PrePostTemplateDefaults`, change this out for an `AnnotationTemplateExpressionDefaults`. |
|
* *OAuth 2.0* - `NimbusOpaqueTokenIntrospector` has been deprecated in favor of `SpringOpaqueTokenIntrospector` in order to remove Spring Security OAuth 2.0 Resource Server's reliance on the `oidc-oauth2-sdk` package. |
|
If you are constructing a `NimbusOpaqueTokenIntrospector`, replace it with ``SpringOpaqueTokenIntrospector``'s constructor |
|
* *OAuth 2.0* - `DefaultAuthorizationCodeTokenResponseClient`, `DefaultClientCredentialsTokenResponseClient`, `DefaultJwtBearerTokenResponseClient`, `DefaultPasswordTokenResponseClient`, `DefaultRefreshTokenTokenResponseClient`, and `DefaultTokenExchangeTokenResponseClient` are deprecated in favor of their `RestClient` equivalents. |
|
+ |
|
Relatedly,`JwtBearerGrantRequestEntityConverter`, `OAuth2AuthorizationCodeGrantRequestEntityConverter`, `OAuth2ClientCredentialsGrantRequestEntityConverter`, `OAuth2PasswordGrantRequestEntityConverter`, `OAuth2RefreshTokenGrantRequestEntityConverter` are deprecated in favor of providing an instance of `DefaultOAuth2TokenRequestParametersConverter` to one of the above token response clients |
|
+ |
|
For example, if you have the following arrangement: |
|
+ |
|
[source,java] |
|
---- |
|
private static class MyCustomConverter |
|
extends AbstractOAuth2AuthorizationGrantRequestEntityConverter<OAuth2AuthorizationCodeGrantRequest> { |
|
@Override |
|
protected MultiValueMap<String, String> createParameters |
|
(OAuth2AuthorizationCodeGrantRequest request) { |
|
MultiValueMap<String, String> parameters = super.createParameters(request); |
|
parameters.add("custom", "value"); |
|
return parameters; |
|
} |
|
} |
|
|
|
@Bean |
|
OAuth2AccessTokenResponseClient authorizationCode() { |
|
DefaultAuthorizationCodeTokenResponseClient client = |
|
new DefaultAuthorizationCodeTokenResponseClient(); |
|
Converter<AuthorizationCodeGrantRequest, RequestEntity<?>> entityConverter = |
|
new OAuth2AuthorizationCodeGrantRequestEntityConverter(); |
|
entityConverter.setParametersConverter(new MyCustomConverter()); |
|
client.setRequestEntityConverter(entityConverter); |
|
return client; |
|
} |
|
---- |
|
+ |
|
This configuration is deprecated since it uses `DefaultAuthorizationCodeTokenResponseClient` and `OAuth2AuthorizationCodeGrantRequestEntityConverter`. |
|
The recommended configuration is now: |
|
+ |
|
[source,java] |
|
---- |
|
private static class MyCustomConverter implements Converter<OAuth2AuthorizationCodeGrantRequest, Map<String, String>> { |
|
@Override |
|
public MultiValueMap<String, String> convert(OAuth2AuthorizeCodeGrantRequest request) { |
|
MultiValueMap<String, String> parameters = OAuth2AuthorizationCodeGrantRequest.defaultParameters(request); |
|
parameters.add("custom", "value"); |
|
return parameters; |
|
} |
|
} |
|
|
|
@Bean |
|
OAuth2AccessTokenResponseClient authorizationCode() { |
|
RestClientAuthorizationCodeTokenResponseClient client = |
|
new RestClientAuthorizationCodeTokenResponseClient(); |
|
client.setParametersConverter(new MyCustomConverter()); |
|
return client; |
|
} |
|
---- |
|
|
|
|
|
* *SAML 2.0* - Unversioned OpenSAML implementations of Spring Security SAML 2.0 Service Provider's interfaces have been deprecated in favor of versioned ones. |
|
For example, `OpenSamlAuthenticationTokenConverter` is now replaced by `OpenSaml4AuthenticationTokenConverter` and `OpenSaml5AuthenticationTokenConverter`. |
|
If you are constructing one of these deprecated versions, please replace it with the one that corresponds to the OpenSAML version you are using. |
|
* *SAML 2.0* - Methods surrounding `AssertingPartyDetails` are deprecated in favor of equivalent methods that use the `AssertingPartyMetadata` interface. |
|
* *LDAP* - Usages of `DistinguishedName` are now deprecated in order to align with Spring LDAP's deprecations |
|
|
|
== One-Time Token Login |
|
|
|
* Spring Security now xref:servlet/authentication/onetimetoken.adoc[supports One-Time Token Login] via the `oneTimeTokenLogin()` DSL, including xref:servlet/authentication/onetimetoken.adoc#customize-generate-consume-token[JDBC support]. |
|
|
|
== Passkeys |
|
|
|
Spring Security now has xref:servlet/authentication/passkeys.adoc[Passkeys] support. |
|
|
|
== Method Security |
|
|
|
* All xref:servlet/authorization/method-security.adoc#meta-annotations[method security annotations] now support {spring-framework-api-url}org/springframework/core/annotation/AliasFor.html[Framework's `@AliasFor`] |
|
* `@AuthenticationPrincipal` and `@CurrentSecurityContext` now support xref:servlet/authorization/method-security.adoc#_templating_meta_annotation_expressions[annotation templates]. |
|
+ |
|
This means that you can now use Spring's meta-annotation support like so: |
|
+ |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Target(TargetType.TYPE) |
|
@Retention(RetentionPolicy.RUNTIME) |
|
@AuthenticationPrincipal("claims['{claim}']") |
|
@interface CurrentUsername { |
|
String claim() default "sub"; |
|
} |
|
|
|
// ... |
|
|
|
@GetMapping |
|
public String method(@CurrentUsername("username") String username) { |
|
// ... |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
annotation CurrentUsername(val claim: String = "sub") |
|
|
|
// ... |
|
|
|
@GetMapping |
|
fun method(@CurrentUsername("username") val username: String): String { |
|
// ... |
|
} |
|
---- |
|
====== |
|
* https://github.com/spring-projects/spring-security/issues/13490[Several] https://github.com/spring-projects/spring-security/issues/13234[improvements] https://github.com/spring-projects/spring-security/issues/15097[were made] to align Security's annotation search with ``AbstractFallbackMethodSecurityMetadataSource``'s algorithm. |
|
This aids in migration from earlier versions of Spring Security. |
|
* Native applications can now xref:servlet/authorization/method-security.adoc#authorize-return-object-aot[use `@AuthorizeReturnObject`] |
|
* Native applications can now xref:servlet/authorization/method-security.adoc#pre-post-authorize-aot[reference beans in `@PreAuthorize` and `@PostAuthorize`] |
|
* `SecurityAnnotationScanners` offers https://github.com/spring-projects/spring-security/issues/15700[a convenient API] for scanning for Security annotations and for adding Security's selection and templating features to custom annotations |
|
|
|
== OAuth 2.0 |
|
|
|
* `oauth2Login()` now accepts https://github.com/spring-projects/spring-security/pull/15237[`OAuth2AuthorizationRequestResolver` as a `@Bean`] |
|
* `ClientRegistrations` now supports externally obtained configuration |
|
* Added `loginPage()` to DSL in reactive `oauth2Login()` |
|
* OIDC Back-Channel support now accepts https://github.com/spring-projects/spring-security/issues/15003[logout tokens of type `logout+jwt`] |
|
* `RestClient` can now be xref:servlet/oauth2/index.adoc#oauth2-client-access-protected-resources[configured] with `OAuth2ClientHttpRequestInterceptor` to xref:servlet/oauth2/index.adoc#oauth2-client-accessing-protected-resources-example[make protected resources requests] |
|
* Added `RestClient`-based implementations of `OAuth2AccessTokenResponseClient` for more consistent configuration of access token requests. |
|
+ |
|
To opt-in to using `RestClient` support, simply publish a bean for each grant type as in the following example: |
|
+ |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
public class SecurityConfig { |
|
|
|
@Bean |
|
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() { |
|
return new RestClientAuthorizationCodeTokenResponseClient(); |
|
} |
|
|
|
@Bean |
|
public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() { |
|
return new RestClientRefreshTokenTokenResponseClient(); |
|
} |
|
|
|
@Bean |
|
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() { |
|
return new RestClientClientCredentialsTokenResponseClient(); |
|
} |
|
|
|
@Bean |
|
public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() { |
|
return new RestClientJwtBearerTokenResponseClient(); |
|
} |
|
|
|
@Bean |
|
public OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeAccessTokenResponseClient() { |
|
return new RestClientTokenExchangeTokenResponseClient(); |
|
} |
|
|
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
class SecurityConfig { |
|
|
|
@Bean |
|
fun authorizationCodeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> { |
|
return RestClientAuthorizationCodeTokenResponseClient() |
|
} |
|
|
|
@Bean |
|
fun refreshTokenAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> { |
|
return RestClientRefreshTokenTokenResponseClient() |
|
} |
|
|
|
@Bean |
|
fun clientCredentialsAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> { |
|
return RestClientClientCredentialsTokenResponseClient() |
|
} |
|
|
|
@Bean |
|
fun jwtBearerAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> { |
|
return RestClientJwtBearerTokenResponseClient() |
|
} |
|
|
|
@Bean |
|
fun tokenExchangeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> { |
|
return RestClientTokenExchangeTokenResponseClient() |
|
} |
|
|
|
} |
|
---- |
|
====== |
|
* Token Exchange now https://github.com/spring-projects/spring-security/issues/15534[supports refresh tokens] |
|
|
|
== SAML 2.0 |
|
|
|
* Added xref:servlet/saml2/opensaml.adoc[OpenSAML 5 Support]. |
|
Now you can use either OpenSAML 4 or OpenSAML 5; by default, Spring Security will select the write implementations based on what's on your classpath. |
|
* Using EntityIDs for the `registrationId` is simplified. |
|
+ |
|
A common pattern is to identify asserting parties by their `entityID`. |
|
In previous versions, this required directly configuring `OpenSamlAuthenticationRequestResolver`. |
|
Now, the request resolver looks by default for the `registrationId` https://github.com/spring-projects/spring-security/issues/15017[as a request parameter] in addition to looking for it in the path. |
|
This allows you to use `RelyingPartyRegistrations` or `OpenSaml4/5AssertingPartyMetadataRepository` without also needing to modify the `registrationId` values or customize the request resolver. |
|
+ |
|
Relatedly, you can now configure your `authenticationRequestUri` to xref:servlet/saml2/login/authentication-requests.adoc#configuring-authentication-request-uri[contain a query parameter] |
|
* Asserting Parties can now be refreshed in the background according to the metadata's expiry. |
|
+ |
|
For example, you can now use xref:servlet/saml2/metadata.adoc#using-assertingpartymetadatarepository[`OpenSaml5AssertingPartyMetadataRepository`] to do: |
|
+ |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Component |
|
public class RefreshableRelyingPartyRegistrationRepository implements IterableRelyingPartyRegistrationRepository { |
|
private final AssertingPartyMetadataRepository assertingParties = OpenSaml5AssertingPartyMetadataRepository |
|
.fromTrustedMetadataLocation("https://idp.example.org").build(); |
|
|
|
@Override |
|
public RelyingPartyRegistration findByRegistrationId(String registrationId) { |
|
AssertingPartyMetadata assertingParty = this.assertingParties.findByEntityId(registrationId); |
|
return RelyingPartyRegistration.withAssertingPartyMetadata(assertingParty) |
|
// relying party configurations |
|
.build(); |
|
} |
|
|
|
// ... |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Component |
|
open class RefreshableRelyingPartyRegistrationRepository: IterableRelyingPartyRegistrationRepository { |
|
private val assertingParties: AssertingPartyMetadataRepository = OpenSaml5AssertingPartyMetadataRepository |
|
.fromTrustedMetadataLocation("https://idp.example.org").build() |
|
|
|
override fun findByRegistrationId(String registrationId): RelyingPartyRegistration { |
|
val assertingParty = this.assertingParties.findByEntityId(registrationId) |
|
return RelyingPartyRegistration.withAssertingPartyMetadata(assertingParty) |
|
// relying party configurations |
|
.build() |
|
} |
|
|
|
// ... |
|
} |
|
---- |
|
====== |
|
+ |
|
This implementation also supports the validation of a metadata's signature. |
|
* You can now sign https://github.com/spring-projects/spring-security/pull/14916[relying party metadata] |
|
* `RelyingPartyRegistrationRepository` results can now be javadoc:org.springframework.security.saml2.provider.service.registration.CachingRelyingPartyRegistrationRepository[cached]. |
|
This is helpful if you want to defer the loading of the registration values til after application startup. |
|
It is also helpful if you want to control when metadata gets refreshed via Spring Cache. |
|
* To align with the SAML 2.0 standard, the metadata endpoint now https://github.com/spring-projects/spring-security/issues/15147[uses the `application/samlmetadata+xml` MIME type] |
|
|
|
== Web |
|
|
|
* CSRF BREACH tokens are now https://github.com/spring-projects/spring-security/issues/15187[more consistent] |
|
* The Remember Me cookie now is https://github.com/spring-projects/spring-security/pull/15203[more customizable] |
|
* Security Filter Chain finds more invalid configurations. |
|
For example, a filter chain declared after an any-request filter chain is invalid since it will never be invoked: |
|
+ |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
@Order(0) |
|
SecurityFilterChain api(HttpSecurity http) throws Exception { |
|
http |
|
// implicit securityMatcher("/**") |
|
.authorizeHttpRequests(...) |
|
.httpBasic(...) |
|
|
|
return http.build(); |
|
} |
|
|
|
@Bean |
|
@Order(1) |
|
SecurityFilterChain app(HttpSecurity http) throws Exception { |
|
http |
|
.securityMatcher("/app/**") |
|
.authorizeHttpRequests(...) |
|
.formLogin(...) |
|
|
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
@Order(0) |
|
fun api(val http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
authorizeHttpRequests { |
|
// ... |
|
} |
|
} |
|
return http.build() |
|
} |
|
|
|
@Bean |
|
@Order(1) |
|
fun app(val http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
securityMatcher("/app/**") |
|
authorizeHttpRequests { |
|
// ... |
|
} |
|
} |
|
return http.build() |
|
} |
|
---- |
|
====== |
|
You can read more https://github.com/spring-projects/spring-security/issues/15220[in the related ticket]. |
|
* `ServerHttpSecurity` now https://github.com/spring-projects/spring-security/issues/15974[picks up `ServerWebExchangeFirewall` as a `@Bean`] |
|
|
|
== Observability |
|
|
|
Observability now supports xref:servlet/integrations/observability.adoc#observability-tracing-disable[toggling authorization, authentication, and request observations separately] |
|
For example, to turn off filter chain observations, you can publish a `@Bean` like this one: |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityObservationSettings allSpringSecurityObservations() { |
|
return SecurityObservationSettings.withDefaults() |
|
.shouldObserveFilterChains(false).build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun allSpringSecurityObservations(): SecurityObservationSettings { |
|
return SecurityObservationSettings.builder() |
|
.shouldObserveFilterChains(false).build() |
|
} |
|
---- |
|
====== |
|
|
|
== Kotlin |
|
|
|
* The Kotlin DSL now supports https://github.com/spring-projects/spring-security/issues/14935[SAML 2.0] and https://github.com/spring-projects/spring-security/issues/15171[`GrantedAuthorityDefaults`] and https://github.com/spring-projects/spring-security/issues/15136[`RoleHierarchy`] ``@Bean``s |
|
* `@PreFilter` and `@PostFilter` are https://github.com/spring-projects/spring-security/pull/15095[now supported] in Kotlin |
|
* The Kotlin Reactive DSL now supports https://github.com/spring-projects/spring-security/pull/15013[`SecurityContextRepository`] |
|
|
|
== Acl |
|
|
|
* `AclAuthorizationStrategyImpl` now https://github.com/spring-projects/spring-security/issues/4186[supports `RoleHierarchy`]
|
|
|