Add 7.0 -> 8.0 Migration Guide

Closes gh-17182
This commit is contained in:
Josh Cummings 2025-05-28 15:48:17 -06:00
parent 215547f8c8
commit 37a814bc29
No known key found for this signature in database
GPG Key ID: 869B37A20E876129
16 changed files with 98 additions and 1636 deletions

View File

@ -2,14 +2,11 @@
* xref:prerequisites.adoc[Prerequisites]
* xref:community.adoc[Community]
* xref:whats-new.adoc[What's New]
* xref:migration-7/index.adoc[Preparing for 7.0]
** xref:migration-7/authentication.adoc[Authentication]
** xref:migration-7/authorization.adoc[Authorization]
** xref:migration-7/configuration.adoc[Configuration]
** xref:migration-7/ldap.adoc[LDAP]
** xref:migration-7/oauth2.adoc[OAuth 2.0]
** xref:migration-7/web.adoc[Web]
* xref:migration/index.adoc[Migrating to 6]
* xref:migration-8/index.adoc[Preparing for 8.0]
* xref:migration/index.adoc[Migrating to 7]
** xref:migration/servlet/index.adoc[Servlet]
*** xref:migration/servlet/oauth2.adoc[OAuth 2.0]
** xref:migration/reactive.adoc[Reactive]
* xref:getting-spring-security.adoc[Getting Spring Security]
* xref:attachment$api/java/index.html[Javadoc]
* xref:features/index.adoc[Features]

View File

@ -1,68 +0,0 @@
= Authentication Changes
== Opaque Token Credentials Will Be Encoded For You
In order to comply more closely with the Introspection RFC, Spring Security's opaque token support will encode the client id and secret before creating the authorization header.
This change means you will no longer have to encode the client id and secret yourself.
If your client id or secret contain URL-unsafe characters, then you can prepare yourself for this change by doing the following:
=== Replace Usage of `introspectionClientCredentials`
Since Spring Security can now do the encoding for you, replace xref:servlet/oauth2/resource-server/opaque-token.adoc#oauth2resourceserver-opaque-introspectionuri-dsl[using `introspectionClientCredentials`] with publishing the following `@Bean`:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
OpaqueTokenIntrospector introspector() {
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build();
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun introspector(): OpaqueTokenIntrospector {
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build()
}
----
======
The above will be the default in 7.0.
If this setting gives you trouble or you cannot apply it for now, you can use the `RestOperations` constructor instead:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
OpaqueTokenIntrospector introspector() {
RestTemplate rest = new RestTemplate();
rest.addInterceptor(new BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret));
return new SpringOpaqueTokenIntrospector(introspectionUri, rest);
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun introspector(): OpaqueTokenIntrospector {
val rest = RestTemplate()
rest.addInterceptor(BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret))
return SpringOpaqueTokenIntrospector(introspectionUri, rest)
}
----
======

View File

@ -1,24 +0,0 @@
= Authorization Changes
The following sections relate to how to adapt to changes in the authorization support.
== Method Security
[[compile-with-parameters]]
=== Compile With `-parameters`
Spring Framework 6.1 https://github.com/spring-projects/spring-framework/issues/29559[removes LocalVariableTableParameterNameDiscoverer].
This affects how `@PreAuthorize` and other xref:servlet/authorization/method-security.adoc[method security] annotations will process parameter names.
If you are using method security annotations with parameter names, for example:
[source,java]
.Method security annotation using `id` parameter name
----
@PreAuthorize("@authz.checkPermission(#id, authentication)")
public void doSomething(Long id) {
// ...
}
----
You must compile with `-parameters` to ensure that the parameter names are available at runtime.
For more information about this, please visit the https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#core-container[Upgrading to Spring Framework 6.1 page].

View File

@ -1,125 +0,0 @@
= Configuration Migrations
The following steps relate to changes around how to configure `HttpSecurity`, `WebSecurity` and related components.
== Use the Lambda DSL
The Lambda DSL is present in Spring Security since version 5.2, and it allows HTTP security to be configured using lambdas.
You may have seen this style of configuration in the Spring Security documentation or samples.
Let us take a look at how a lambda configuration of HTTP security compares to the previous configuration style.
[source,java]
.Configuration using lambdas
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/blog/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin
.loginPage("/login")
.permitAll()
)
.rememberMe(Customizer.withDefaults());
return http.build();
}
}
----
[source,java]
.Equivalent configuration without using lambdas
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.requestMatchers("/blog/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.rememberMe();
return http.build();
}
}
----
The Lambda DSL is the preferred way to configure Spring Security, the prior configuration style will not be valid in Spring Security 7 where the usage of the Lambda DSL will be required.
This has been done mainly for a couple of reasons:
- The previous way it was not clear what object was getting configured without knowing what the return type was.
The deeper the nesting the more confusing it became.
Even experienced users would think that their configuration was doing one thing when in fact, it was doing something else.
- Consistency.
Many code bases switched between the two styles which caused inconsistencies that made understanding the configuration difficult and often led to misconfigurations.
=== Lambda DSL Configuration Tips
When comparing the two samples above, you will notice some key differences:
- In the Lambda DSL there is no need to chain configuration options using the `.and()` method.
The `HttpSecurity` instance is automatically returned for further configuration after the call to the lambda method.
- `Customizer.withDefaults()` enables a security feature using the defaults provided by Spring Security.
This is a shortcut for the lambda expression `it -> {}`.
=== WebFlux Security
You may also configure WebFlux security using lambdas in a similar manner.
Below is an example configuration using lambdas.
[source,java]
.WebFlux configuration using lambdas
----
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/blog/**").permitAll()
.anyExchange().authenticated()
)
.httpBasic(Customizer.withDefaults())
.formLogin(formLogin -> formLogin
.loginPage("/login")
);
return http.build();
}
}
----
=== Goals of the Lambda DSL
The Lambda DSL was created to accomplish to following goals:
- Automatic indentation makes the configuration more readable.
- There is no need to chain configuration options using `.and()`
- The Spring Security DSL has a similar configuration style to other Spring DSLs such as Spring Integration and Spring Cloud Gateway.
== Use `.with()` instead of `.apply()` for Custom DSLs
In versions prior to 6.2, if you had a xref:servlet/configuration/java.adoc#jc-custom-dsls[custom DSL], you would apply it to the `HttpSecurity` using the `HttpSecurity#apply(...)` method.
However, starting from version 6.2, this method is deprecated and will be removed in 7.0 because it will no longer be possible to chain configurations using `.and()` once `.and()` is removed (see https://github.com/spring-projects/spring-security/issues/13067).
Instead, it is recommended to use the new `.with(...)` method.
For more information about how to use `.with(...)` please refer to the xref:servlet/configuration/java.adoc#jc-custom-dsls[Custom DSLs section].

View File

@ -1,11 +0,0 @@
= LDAP Migrations
The following steps relate to changes around how to configure the LDAP components and how to use an embedded LDAP server.
== Use `UnboundId` instead of `ApacheDS`
ApacheDS has not had a GA release for a considerable period, and its classes in Spring Security were https://github.com/spring-projects/spring-security/pull/6376[deprecated in version 5.2].
Consequently, support for ApacheDS will be discontinued in version 7.0.
If you are currently using ApacheDS as an embedded LDAP server, we recommend migrating to https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundId].
You can find instructions in xref:servlet/authentication/passwords/ldap.adoc#servlet-authentication-ldap-embedded[this section] that describe how to set up an embedded UnboundId LDAP server.

View File

@ -1,172 +0,0 @@
= OAuth 2.0 Changes
== Validate `typ` Header with `JwtTypeValidator`
`NimbusJwtDecoder` in Spring Security 7 will move `typ` header validation to `JwtTypeValidator` instead of relying on Nimbus.
This brings it in line with `NimbusJwtDecoder` validating claims instead of relying on Nimbus to validate them.
If you are changing Nimbus's default type validation in a `jwtProcessorCustomizer` method, then you should move that to `JwtTypeValidator` or an implementation of `OAuth2TokenValidator` of your own.
To check if you are prepared for this change, add the default `JwtTypeValidator` to your list of validators, as this will be included by default in 7:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.validateTypes(false) <1>
// ... your remaining configuration
.build();
jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
new JwtIssuerValidator(location), JwtTypeValidator.jwt())); <2>
return jwtDecoder;
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun jwtDecoder(): JwtDecoder {
val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.validateTypes(false) <1>
// ... your remaining configuration
.build()
jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
JwtIssuerValidator(location), JwtTypeValidator.jwt())) <2>
return jwtDecoder
}
----
======
<1> - Switch off Nimbus verifying the `typ` (this will be off by default in 7)
<2> - Add the default `typ` validator (this will be included by default in 7)
Note the default value verifies that the `typ` value either be `JWT` or not present, which is the same as the Nimbus default.
It is also aligned with https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.9[RFC 7515] which states that `typ` is optional.
=== I'm Using A `DefaultJOSEObjectTypeVerifier`
If you have something like the following in your configuration:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.jwtProcessorCustomizer((c) -> c
.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>("JOSE"))
)
.build();
return jwtDecoder;
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun jwtDecoder(): JwtDecoder {
val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.jwtProcessorCustomizer {
it.setJWSTypeVerifier(DefaultJOSEObjectTypeVerifier("JOSE"))
}
.build()
return jwtDecoder
}
----
======
Then change this to:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.validateTypes(false)
.build();
jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
new JwtIssuerValidator(location), new JwtTypeValidator("JOSE")));
return jwtDecoder;
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun jwtDecoder(): JwtDecoder {
val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.validateTypes(false)
.build()
jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
JwtIssuerValidator(location), JwtTypeValidator("JOSE")))
return jwtDecoder
}
----
======
To indicate that the `typ` header is optional, use `#setAllowEmpty(true)` (this is the equivalent of including `null` in the list of allowed types in `DefaultJOSEObjectTypeVerifier`).
=== I want to opt-out
If you want to keep doing things the way that you are, then the steps are similar, just in reverse:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.validateTypes(true) <1>
.jwtProcessorCustomizer((c) -> c
.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>("JOSE"))
)
.build();
jwtDecoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(
new JwtTimestampValidator(), new JwtIssuerValidator(location))); <2>
return jwtDecoder;
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun jwtDecoder(): JwtDecoder {
val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.validateTypes(true) <1>
.jwtProcessorCustomizer {
it.setJWSTypeVerifier(DefaultJOSEObjectTypeVerifier("JOSE"))
}
.build()
jwtDecoder.setJwtValidator(DelegatingOAuth2TokenValidator(
JwtTimestampValidator(), JwtIssuerValidator(location))) <2>
return jwtDecoder
}
----
======
<1> - leave Nimbus type verification on
<2> - specify the list of validators you need, excluding `JwtTypeValidator`
For additional guidance, please see the xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-validation[JwtDecoder Validators] section in the reference.

View File

@ -1,165 +0,0 @@
= Saml 2.0 Migrations
== Continue Filter Chain When No Relying Party Found
In Spring Security 6, `Saml2WebSsoAuthenticationFilter` throws an exception when the request URI matches, but no relying party registration is found.
There are a number of cases when an application would not consider this an error situation.
For example, this filter doesn't know how the `AuthorizationFilter` will respond to a missing relying party.
In some cases it may be allowable.
In other cases, you may want your `AuthenticationEntryPoint` to be invoked, which would happen if this filter were to allow the request to continue to the `AuthorizationFilter`.
To improve this filter's flexibility, in Spring Security 7 it will continue the filter chain when there is no relying party registration found instead of throwing an exception.
For many applications, the only notable change will be that your `authenticationEntryPoint` will be invoked if the relying party registration cannot be found.
When you have only one asserting party, this means by default a new authentication request will be built and sent back to the asserting party, which may cause a "Too Many Redirects" loop.
To see if you are affected in this way, you can prepare for this change in 6 by setting the following property in `Saml2WebSsoAuthenticationFilter`:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
http
.saml2Login((saml2) -> saml2
.withObjectPostProcessor(new ObjectPostProcessor<Saml2WebSsoAuhenticaionFilter>() {
@Override
public Saml2WebSsoAuthenticationFilter postProcess(Saml2WebSsoAuthenticationFilter filter) {
filter.setContinueChainWhenNoRelyingPartyRegistrationFound(true);
return filter;
}
})
)
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
http {
saml2Login { }
withObjectPostProcessor(
object : ObjectPostProcessor<Saml2WebSsoAuhenticaionFilter?>() {
override fun postProcess(filter: Saml2WebSsoAuthenticationFilter): Saml2WebSsoAuthenticationFilter {
filter.setContinueChainWhenNoRelyingPartyRegistrationFound(true)
return filter
}
})
}
----
Xml::
+
[source,xml,role="secondary"]
----
<b:bean id="saml2PostProcessor" class="org.example.MySaml2WebSsoAuthenticationFilterBeanPostProcessor"/>
----
======
== Validate Response After Validating Assertions
In Spring Security 6, the order of authenticating a `<saml2:Response>` is as follows:
1. Verify the Response Signature, if any
2. Decrypt the Response
3. Validate Response attributes, like Destination and Issuer
4. For each assertion, verify the signature, decrypt, and then validate its fields
5. Check to ensure that the response has at least one assertion with a name field
This ordering sometimes poses challenges since some response validation is being done in Step 3 and some in Step 5.
Specifically, this poses a chellenge when an application doesn't have a name field and doesn't need it to be validated.
In Spring Security 7, this is simplified by moving response validation to after assertion validation and combining the two separate validation steps 3 and 5.
When this is complete, response validation will no longer check for the existence of the `NameID` attribute and rely on ``ResponseAuthenticationConverter``s to do this.
This will add support ``ResponseAuthenticationConverter``s that don't use the `NameID` element in their `Authentication` instance and so don't need it validated.
To opt-in to this behavior in advance, use `OpenSaml5AuthenticationProvider#setValidateResponseAfterAssertions` to `true` like so:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider();
provider.setValidateResponseAfterAssertions(true);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val provider = OpenSaml5AuthenticationProvider()
provider.setValidateResponseAfterAssertions(true)
----
======
This will change the authentication steps as follows:
1. Verify the Response Signature, if any
2. Decrypt the Response
3. For each assertion, verify the signature, decrypt, and then validate its fields
4. Validate Response attributes, like Destination and Issuer
Note that if you have a custom response authentication converter, then you are now responsible to check if the `NameID` element exists in the event that you need it.
Alternatively to updating your response authentication converter, you can specify a custom `ResponseValidator` that adds back in the check for the `NameID` element as follows:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider();
provider.setValidateResponseAfterAssertions(true);
ResponseValidator responseValidator = ResponseValidator.withDefaults((responseToken) -> {
Response response = responseToken.getResponse();
Assertion assertion = CollectionUtils.firstElement(response.getAssertions());
Saml2Error error = new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND,
"Assertion [" + firstAssertion.getID() + "] is missing a subject");
Saml2ResponseValidationResult failed = Saml2ResponseValidationResult.failure(error);
if (assertion.getSubject() == null) {
return failed;
}
if (assertion.getSubject().getNameID() == null) {
return failed;
}
if (assertion.getSubject().getNameID().getValue() == null) {
return failed;
}
return Saml2ResponseValidationResult.success();
});
provider.setResponseValidator(responseValidator);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val provider = OpenSaml5AuthenticationProvider()
provider.setValidateResponseAfterAssertions(true)
val responseValidator = ResponseValidator.withDefaults { responseToken: ResponseToken ->
val response = responseToken.getResponse()
val assertion = CollectionUtils.firstElement(response.getAssertions())
val error = Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND,
"Assertion [" + firstAssertion.getID() + "] is missing a subject")
val failed = Saml2ResponseValidationResult.failure(error)
if (assertion.getSubject() == null) {
return@withDefaults failed
}
if (assertion.getSubject().getNameID() == null) {
return@withDefaults failed
}
if (assertion.getSubject().getNameID().getValue() == null) {
return@withDefaults failed
}
return@withDefaults Saml2ResponseValidationResult.success()
}
provider.setResponseValidator(responseValidator)
----
======

View File

@ -1,523 +0,0 @@
= Web Migrations
== Favor Relative URIs
When redirecting to a login endpoint, Spring Security has favored absolute URIs in the past.
For example, if you set your login page like so:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
http
// ...
.formLogin((form) -> form.loginPage("/my-login"))
// ...
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
http {
formLogin {
loginPage = "/my-login"
}
}
----
Xml::
+
[source,kotlin,role="secondary"]
----
<http ...>
<form-login login-page="/my-login"/>
</http>
----
======
then when redirecting to `/my-login` Spring Security would use a `Location:` like the following:
[source]
----
302 Found
// ...
Location: https://myapp.example.org/my-login
----
However, this is no longer necessary given that the RFC is was based on is now obsolete.
In Spring Security 7, this is changed to use a relative URI like so:
[source]
----
302 Found
// ...
Location: /my-login
----
Most applications will not notice a difference.
However, in the event that this change causes problems, you can switch back to the Spring Security 6 behavior by setting the `favorRelativeUrls` value:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint("/my-login");
entryPoint.setFavorRelativeUris(false);
http
// ...
.exceptionHandling((exceptions) -> exceptions.authenticaitonEntryPoint(entryPoint))
// ...
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
LoginUrlAuthenticationEntryPoint entryPoint = LoginUrlAuthenticationEntryPoint("/my-login")
entryPoint.setFavorRelativeUris(false)
http {
exceptionHandling {
authenticationEntryPoint = entryPoint
}
}
----
Xml::
+
[source,xml,role="secondary"]
----
<http entry-point-ref="myEntryPoint">
<!-- ... -->
</http>
<b:bean id="myEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<b:property name="favorRelativeUris" value="true"/>
</b:bean>
----
======
== PortResolver
Spring Security uses an API called `PortResolver` to provide a workaround for a bug in Internet Explorer.
The workaround is no longer necessary and can cause users problems in some scenarios.
For this reason, Spring Security 7 will remove the `PortResolver` interface.
To prepare for this change, users should expose the `PortResolver.NO_OP` as a Bean named `portResolver`.
This ensures that the `PortResolver` implementation that is used is a no-op (e.g. does nothing) which simulates the removal of `PortResolver`.
An example configuration can be found below:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
PortResolver portResolver() {
return PortResolver.NO_OP;
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
open fun portResolver(): PortResolver {
return PortResolver.NO_OP
}
----
Xml::
+
[source,xml,role="secondary"]
----
<util:constant id="portResolver"
static-field="org.springframework.security.web.PortResolver.NO_OP">
----
======
[[use-path-pattern]]
== Use PathPatternRequestMatcher by Default
In Spring Security 7, `AntPathRequestMatcher` and `MvcRequestMatcher` are no longer supported and the Java DSL requires that all URIs be absolute (less any context root).
At that time, Spring Security 7 will use `PathPatternRequestMatcher` by default.
To check how prepared you are for this change, you can publish this bean:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun requestMatcherBuilder(): PathPatternRequestMatcherBuilderFactoryBean {
return PathPatternRequestMatcherBuilderFactoryBean()
}
----
Xml::
+
[source,xml,role="secondary"]
----
<b:bean class="org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean"/>
----
======
This will tell the Spring Security DSL to use `PathPatternRequestMatcher` for all request matchers that it constructs.
In the event that you are directly constructing an object (as opposed to having the DSL construct it) that has a `setRequestMatcher` method. you should also proactively specify a `PathPatternRequestMatcher` there as well.
=== Migrate `exitUserUrl` and `switchUserUrl` Request Matchers in `SwitchUserFilter`
`SwitchUserFilter`, constructs an `AntPathRequestMatcher` in its `setExitUserUrl` and `setSwitchUserUrl` methods.
This will change to use `PathPatternRequestMatcher` in Spring Security 7.
To prepare for this change, call `setExitUserMatcher` and `setSwithcUserMatcher` to provide this `PathPatternRequestMatcher` in advance.
That is, change this:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
SwitchUserFilter switchUser = new SwitchUserFilter();
// ... other configuration
switchUser.setExitUserUrl("/exit/impersonate");
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val switchUser = SwitchUserFilter()
// ... other configuration
switchUser.setExitUserUrl("/exit/impersonate")
----
======
to this:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
SwitchUserFilter switchUser = new SwitchUserFilter();
// ... other configuration
switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"));
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val switchUser = SwitchUserFilter()
// ... other configuration
switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"))
----
======
=== Migrate `filterProcessingUrl` Request Matcher in `AbstractAuthenticationProcessingFilter` Implementations
Spring Security 6 converts any processing endpoint configured through `setFilterProcessingUrl` to an `AntPathRequestMatcher`.
In Spring Security 7, this will change to `PathPatternRequestMatcher`.
If you are directly invoking `setFilterProcessingUrl` on a filter that extends `AbstractAuthenticationProcessingFilter`, like `UsernamePasswordAuthenticationFilter`, `OAuth2LoginAuthenticationFilter`, `Saml2WebSsoAuthenticationFilter`, `OneTimeTokenAuthenticationFilter`, or `WebAuthnAuthenticationFilter`, call `setRequiredAuthenticationRequestMatcher` instead to provide this `PathPatternRequestMatcher` in advance.
That is, change this:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
usernamePassword.setFilterProcessingUrl("/my/processing/url");
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
usernamePassword.setFilterProcessingUrl("/my/processing/url")
----
======
to this:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
RequestMatcher requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url");
usernamePassword.setRequest(requestMatcher);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
val requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url")
usernamePassword.setRequest(requestMatcher)
----
======
[NOTE]
-----
Most applications use the DSL instead of setting the `filterProcessingUrl` directly on a filter instance.
-----
=== Migrate CAS Proxy Receptor Request Matcher
Spring Security 6 converts any configured `proxyReceptorUrl` to a request matcher that matches the end of the request, that is `/**/proxy/receptor`.
In Spring Security 7, this pattern is not allowed and will change to using `PathPatternRequestMatcher`.
Also in Spring Security 7m the URL should by absolute, excluding any context path, like so: `/proxy/receptor`.
So to prepare for these change, you can use `setProxyReceptorRequestMatcher` instead of `setProxyReceptorUrl`.
That is, change this:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
casAuthentication.setProxyReceptorUrl("/proxy/receptor");
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
casAuthentication.setProxyReceptorUrl("/proxy/receptor")
----
======
to this:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"));
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"))
----
======
=== Migrate your WebInvocationPrivilegeEvaluator
If you are using Spring Security's JSP Taglibs or are using `WebInvocationPrivilegeEvaluator` directly, be aware of the following changes:
1. `RequestMatcherWebInvocationPrivilegeEvaluator` is deprecated in favor of `AuthorizationManagerWebInvocationPrivilegeEvaluator`
2. `HandlerMappingIntrospectorRequestTransformer` is deprecated in favor of `PathPatternRequestTransformer`
If you are not constructing these directly, you can opt-in to both changes in advance by publishing a `PathPatternRequestTransformer` like so:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
HttpServletRequestTransformer pathPatternRequestTransformer() {
return new PathPatternRequestTransformer();
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun pathPatternRequestTransformer(): HttpServletRequestTransformer {
return PathPatternRequestTransformer()
}
----
Xml::
+
[source,xml,role="secondary"]
----
<b:bean class="org.springframework.security.web.access.PathPatternRequestTransformer"/>
----
======
Spring Security will take this as a signal to use the new implementations.
[[NOTE]]
----
One difference you may notice is that `AuthorizationManagerWebPrivilegeInvocationEvaluator` allows the authentication to be `null` if the authorization rule is `permitAll`.
Test your endpoints that `permitAll` in case JSP requests using this same require should not, in fact, be permitted.
----
== Include the Servlet Path Prefix in Authorization Rules
For many applications <<use-path-pattern, the above>> will make no difference since most commonly all URIs listed are matched by the default servlet.
However, if you have other servlets with servlet path prefixes, xref:servlet/authorization/authorize-http-requests.adoc[then these paths now need to be supplied separately].
For example, if I have a Spring MVC controller with `@RequestMapping("/orders")` and my MVC application is deployed to `/mvc` (instead of the default servlet), then the URI for this endpoint is `/mvc/orders`.
Historically, the Java DSL hasn't had a simple way to specify the servlet path prefix and Spring Security attempted to infer it.
Over time, we learned that these inference would surprise developers.
Instead of taking this responsibility away from developers, now it is simpler to specify the servlet path prefix like so:
[method,java]
----
PathPatternRequestParser.Builder servlet = PathPatternRequestParser.withDefaults().basePath("/mvc");
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated()
)
----
For paths that belong to the default servlet, use `PathPatternRequestParser.withDefaults()` instead:
[method,java]
----
PathPatternRequestParser.Builder request = PathPatternRequestParser.withDefaults();
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(request.pattern("/js/**").matcher()).authenticated()
)
----
Note that this doesn't address every kind of servlet since not all servlets have a path prefix.
For example, expressions that match the JSP Servlet might use an ant pattern `/**/*.jsp`.
There is not yet a general-purpose replacement for these, and so you are encouraged to use `RegexRequestMatcher`, like so: `regexMatcher("\\.jsp$")`.
For many applications this will make no difference since most commonly all URIs listed are matched by the default servlet.
[[use-redirect-to-https]]
== Use RedirectToHttps Instead of Channel Security
Years ago, HTTPS at large was enough of a performance and configuration concern that applications wanted to be able to decide which segments of an application would require HTTPS.
`requires-channel` in XML and `requiresChannel` in Java Config allowed configurating an application with that in mind:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
http
.requiresChannel((channel) -> channel
.requestMatchers("/secure/**").requiresSecureChannel()
.requestMatchers("/insecure/**").requiresInsecureChannel()
)
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
http {
requiresChannel {
secure("/secure/**")
seccure("/insecure/**", "REQUIRES_INSECURE_CHANNEL")
}
}
----
Xml::
+
[source,xml,role="secondary"]
----
<http>
<intercept-url pattern="/secure/**" access="authenticated" requires-channel="REQUIRES_SECURE_CHANNEL"/>
<intercept-url pattern="/insecure/**" access="authenticated" requires-channel="REQUIRES_INSECURE_CHANNEL"/>
</http>
----
======
Modern applications should either always require HTTPS.
However, there are times, like when developing locally, when one would like the application to use HTTP.
Or, you may have continuing circumstances that require part of your application to be HTTP.
In any case, you can migrate to `redirect-to-https-request-matcher-ref` and `redirectToHttps` by first constructing a `RequestMatcher` that contains all circumstances where redirecting to HTTPS is needed.
Then you can reference that request matcher like so:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
http
.redirectToHttps((https) -> https.requestMatchers("/secure/**"))
// ...
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
var secure: RequestMatcher = PathPatternRequestMatcher.withDefaults().pattern("/secure/**")
http {
redirectToHttps {
requestMatchers = secure
}
// ...
}
----
Xml::
+
[source,xml,role="secondary"]
----
<b:bean id="builder" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher$Builder"/>
<b:bean id="secure" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher" factory-bean="builder" factory-method="matcher">
<b:constructor-arg value="/secure/**"/>
</b:bean>
<http redirect-to-https-request-matcher-ref="secure">
<intercept-url pattern="/secure/**" access="authenticated"/>
<intercept-url pattern="/insecure/**" access="authenticated"/>
<!-- ... -->
</http>
----
======
[TIP]
=====
If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance.
=====

View File

@ -1,9 +1,9 @@
[[preparing]]
= Preparing for 7.0
= Preparing for 8.0
:page-section-summary-toc: 1
While Spring Security 7.0 does not have a release date yet, it is important to start preparing for it now.
While Spring Security 8.0 does not have a release date yet, it is important to start preparing for it now.
This preparation guide is designed to summarize the biggest changes in Spring Security 7.0 and provide steps to prepare for them.
This preparation guide is designed to summarize the biggest changes in Spring Security 8.0 and provide steps to prepare for them.
It is important to keep your application up to date with the latest Spring Security 6 and Spring Boot 3 releases.
It is important to keep your application up to date with the latest Spring Security 7 and Spring Boot 4 releases.

View File

@ -1,34 +1,20 @@
[[migration]]
= Migrating to 6.0
= Migrating to 7.0
:spring-security-reference-base-url: https://docs.spring.io/spring-security/reference
The Spring Security team has prepared the 5.8 release to simplify upgrading to Spring Security 6.0.
Use 5.8 and
ifdef::spring-security-version[]
{spring-security-reference-base-url}/5.8/migration/index.html[its preparation steps]
endif::[]
ifndef::spring-security-version[]
its preparation steps
endif::[]
to simplify updating to 6.0.
Spring Security 6.5 is the last release in the 6.x generation of Spring Security.
It provides strategies for configuring breaking changes to use the 7.0 way before updating.
We recommend you use 6.5 and {spring-security-reference-base-url}/6.5/migration-7/index.html[its preparation steps] to simplify updating to 7.0.
After updating to 5.8, follow this guide to perform any remaining migration or cleanup steps.
After updating to 6.5, follow this guide to perform any remaining migration or cleanup steps.
And recall that if you run into trouble, the preparation guide includes opt-out steps to revert to 5.x behaviors.
== Update to Spring Security 6
== Update to Spring Security 7
The first step is to ensure you are the latest patch release of Spring Boot 3.0.
Next, you should ensure you are on the latest patch release of Spring Security 6.
For directions, on how to update to Spring Security 6 visit the xref:getting-spring-security.adoc[] section of the reference guide.
== Update Package Names
Now that you are updated, you need to change your `javax` imports to `jakarta` imports.
== Compile With `--parameters`
If you are using method parameter names in `@PreAuthorize`, `@PostAuthorize`, or any other method security annotations, you may need to xref:migration/servlet/authorization.adoc#compile-with-parameters[compile with `-parameters`].
The first step is to ensure you are the latest patch release of Spring Boot 4.0.
Next, you should ensure you are on the latest patch release of Spring Security 7.
For directions, on how to update to Spring Security 7 visit the xref:getting-spring-security.adoc[] section of the reference guide.
== Perform Application-Specific Steps

View File

@ -1,100 +1,3 @@
= Reactive
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.
== Use `AuthorizationManager` for Method Security
In 6.0, `@EnableReactiveMethodSecurity` defaults `useAuthorizationManager` to `true`.
So, to complete migration, {security-api-url}org/springframework/security/config/annotation/method/configuration/EnableReactiveMethodSecurity.html[`@EnableReactiveMethodSecurity`] remove the `useAuthorizationManager` attribute:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@EnableReactiveMethodSecurity(useAuthorizationManager = true)
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@EnableReactiveMethodSecurity(useAuthorizationManager = true)
----
======
changes to:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@EnableReactiveMethodSecurity
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@EnableReactiveMethodSecurity
----
======
== Propagate ``AuthenticationServiceException``s
{security-api-url}org/springframework/security/web/server/authentication/AuthenticationWebFilter.html[`AuthenticationWebFilter`] 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.
So, if you opted into this behavior by setting `rethrowAuthenticationServiceException` too `true`, you can now remove it like so:
[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)
----
======
changes to:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
AuthenticationFailureHandler bearerFailureHandler = new ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint);
AuthenticationFailureHandler basicFailureHandler = new ServerAuthenticationEntryPointFailureHandler(basicEntryPoint);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val bearerFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint)
val basicFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(basicEntryPoint)
----
======
[NOTE]
====
If you configured the `ServerAuthenticationFailureHandler` only for the purpose of updating to 6.0, you can remove it completely.
====

View File

@ -1,187 +0,0 @@
= Authentication Migrations
The following steps relate to how to finish migrating authentication support.
== Propagate ``AuthenticationServiceException``s
{security-api-url}org/springframework/security/web/authentication/AuthenticationFilter.html[`AuthenticationFilter`] propagates {security-api-url}org/springframework/security/authentication/AuthenticationServiceException.html[``AuthenticationServiceException``]s to the {security-api-url}org/springframework/security/web/AuthenticationEntryPoint.html[`AuthenticationEntryPoint`].
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.
So, if you opted into this behavior by setting `rethrowAuthenticationServiceException` to `true`, you can now remove it like so:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
AuthenticationFilter authenticationFilter = new AuthenticationFilter(...);
AuthenticationEntryPointFailureHandler handler = new AuthenticationEntryPointFailureHandler(...);
handler.setRethrowAuthenticationServiceException(true);
authenticationFilter.setAuthenticationFailureHandler(handler);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val authenticationFilter: AuthenticationFilter = AuthenticationFilter(...)
val handler: AuthenticationEntryPointFailureHandler = AuthenticationEntryPointFailureHandler(...)
handler.setRethrowAuthenticationServiceException(true)
authenticationFilter.setAuthenticationFailureHandler(handler)
----
Xml::
+
[source,xml,role="secondary"]
----
<bean id="authenticationFilter" class="org.springframework.security.web.authentication.AuthenticationFilter">
<!-- ... -->
<property ref="authenticationFailureHandler"/>
</bean>
<bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler">
<property name="rethrowAuthenticationServiceException" value="true"/>
</bean>
----
======
changes to:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
AuthenticationFilter authenticationFilter = new AuthenticationFilter(...);
AuthenticationEntryPointFailureHandler handler = new AuthenticationEntryPointFailureHandler(...);
authenticationFilter.setAuthenticationFailureHandler(handler);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val authenticationFilter: AuthenticationFilter = AuthenticationFilter(...)
val handler: AuthenticationEntryPointFailureHandler = AuthenticationEntryPointFailureHandler(...)
authenticationFilter.setAuthenticationFailureHandler(handler)
----
Xml::
+
[source,xml,role="secondary"]
----
<bean id="authenticationFilter" class="org.springframework.security.web.authentication.AuthenticationFilter">
<!-- ... -->
<property ref="authenticationFailureHandler"/>
</bean>
<bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler">
<!-- ... -->
</bean>
----
======
[[servlet-opt-in-sha256-rememberme]]
== Use SHA-256 in Remember Me
In 6.0, the `TokenBasedRememberMeServices` uses SHA-256 to encode and match the token.
To complete the migration, any default values can be removed.
For example, if you opted in to the 6.0 default for `encodingAlgorithm` and `matchingAlgorithm` like so:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception {
http
// ...
.rememberMe((remember) -> remember
.rememberMeServices(rememberMeServices)
);
return http.build();
}
@Bean
RememberMeServices rememberMeServices(UserDetailsService userDetailsService) {
RememberMeTokenAlgorithm encodingAlgorithm = RememberMeTokenAlgorithm.SHA256;
TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices(myKey, userDetailsService, encodingAlgorithm);
rememberMe.setMatchingAlgorithm(RememberMeTokenAlgorithm.SHA256);
return rememberMe;
}
}
----
XML::
+
[source,xml,role="secondary"]
----
<http>
<remember-me services-ref="rememberMeServices"/>
</http>
<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
<property name="matchingAlgorithm" value="SHA256"/>
<property name="encodingAlgorithm" value="SHA256"/>
</bean>
----
======
then the defaults can be removed:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception {
http
// ...
.rememberMe((remember) -> remember
.rememberMeServices(rememberMeServices)
);
return http.build();
}
@Bean
RememberMeServices rememberMeServices(UserDetailsService userDetailsService) {
return new TokenBasedRememberMeServices(myKey, userDetailsService);
}
}
----
XML::
+
[source,xml,role="secondary"]
----
<http>
<remember-me services-ref="rememberMeServices"/>
</http>
<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>
----
======
== Default authorities for oauth2Login()
In Spring Security 5, the default `GrantedAuthority` given to a user that authenticates with an OAuth2 or OpenID Connect 1.0 provider (via `oauth2Login()`) is `ROLE_USER`.
In Spring Security 6, the default authority given to a user authenticating with an OAuth2 provider is `OAUTH2_USER`.
The default authority given to a user authenticating with an OpenID Connect 1.0 provider is `OIDC_USER`.
If you configured the `GrantedAuthoritiesMapper` only for the purpose of updating to 6.0, you can remove it completely.

View File

@ -1,136 +0,0 @@
= Authorization Migrations
The following steps relate to how to finish migrating authorization support.
== Use `AuthorizationManager` for Method Security
There are no further migration steps for this feature.
== Use `AuthorizationManager` for Message Security
In 6.0, `<websocket-message-broker>` defaults `use-authorization-manager` to `true`.
So, to complete migration, remove any `websocket-message-broker@use-authorization-manager=true` attribute.
For example:
[tabs]
======
Xml::
+
[source,xml,role="primary"]
----
<websocket-message-broker use-authorization-manager="true"/>
----
======
changes to:
[tabs]
======
Xml::
+
[source,xml,role="primary"]
----
<websocket-message-broker/>
----
======
There are no further migrations steps for Java or Kotlin for this feature.
== Use `AuthorizationManager` for Request Security
In 6.0, `<http>` defaults `once-per-request` to `false`, `filter-all-dispatcher-types` to `true`, and `use-authorization-manager` to `true`.
Also, xref:servlet/authorization/authorize-http-requests.adoc[`authorizeHttpRequests#filterAllDispatcherTypes`] defaults to `true`.
So, to complete migration, any defaults values can be removed.
For example, if you opted in to the 6.0 default for `filter-all-dispatcher-types` or `authorizeHttpRequests#filterAllDispatcherTypes` like so:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
http
.authorizeHttpRequests((authorize) -> authorize
.filterAllDispatcherTypes(true)
// ...
)
----
Kotlin::
+
[source,java,role="secondary"]
----
http {
authorizeHttpRequests {
filterAllDispatcherTypes = true
// ...
}
}
----
Xml::
+
[source,xml,role="secondary"]
----
<http use-authorization-manager="true" filter-all-dispatcher-types="true"/>
----
======
then the defaults may be removed:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
http
.authorizeHttpRequests((authorize) -> authorize
// ...
)
----
Kotlin::
+
[source,java,role="secondary"]
----
http {
authorizeHttpRequests {
// ...
}
}
----
Xml::
+
[source,xml,role="secondary"]
----
<http/>
----
======
[NOTE]
====
`once-per-request` applies only when `use-authorization-manager="false"` and `filter-all-dispatcher-types` only applies when `use-authorization-manager="true"`
====
[[compile-with-parameters]]
=== Compile With `-parameters`
Spring Framework 6.1 https://github.com/spring-projects/spring-framework/issues/29559[removes LocalVariableTableParameterNameDiscoverer].
This affects how `@PreAuthorize` and other xref:servlet/authorization/method-security.adoc[method security] annotations will process parameter names.
If you are using method security annotations with parameter names, for example:
[source,java]
.Method security annotation using `id` parameter name
----
@PreAuthorize("@authz.checkPermission(#id, authentication)")
public void doSomething(Long id) {
// ...
}
----
You must compile with `-parameters` to ensure that the parameter names are available at runtime.
For more information about this, please visit the https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#core-container[Upgrading to Spring Framework 6.1 page].

View File

@ -1,44 +0,0 @@
= Exploit Protection Migrations
:spring-security-reference-base-url: https://docs.spring.io/spring-security/reference
The 5.8 migration guide contains several steps for
ifdef::spring-security-version[]
{spring-security-reference-base-url}/5.8/migration/servlet/exploits.html[exploit protection migrations] when updating to 6.0.
endif::[]
ifndef::spring-security-version[]
exploit protection migrations when updating to 6.0.
endif::[]
You are encouraged to follow those steps first.
The following steps relate to how to finish migrating exploit protection support.
== Defer Loading CsrfToken
In Spring Security 5.8, the default `CsrfTokenRequestHandler` for making the `CsrfToken` available to the application is `CsrfTokenRequestAttributeHandler`.
The default for the field `csrfRequestAttributeName` is `null`, which causes the CSRF token to be loaded on every request.
In Spring Security 6, `csrfRequestAttributeName` defaults to `_csrf`.
If you configured the following only for the purpose of updating to 6.0, you can now remove it:
requestHandler.setCsrfRequestAttributeName("_csrf");
== Protect against CSRF BREACH
In Spring Security 5.8, the default `CsrfTokenRequestHandler` for making the `CsrfToken` available to the application is `CsrfTokenRequestAttributeHandler`.
`XorCsrfTokenRequestAttributeHandler` was added to allow opting into CSRF BREACH support.
In Spring Security 6, `XorCsrfTokenRequestAttributeHandler` is the default `CsrfTokenRequestHandler` for making the `CsrfToken` available.
If you configured the `XorCsrfTokenRequestAttributeHandler` only for the purpose of updating to 6.0, you can remove it completely.
[NOTE]
====
If you have set the `csrfRequestAttributeName` to `null` in order to opt out of deferred tokens, or if you have configured a `CsrfTokenRequestHandler` for any other reason, you can leave the configuration in place.
====
== CSRF BREACH with WebSocket support
In Spring Security 5.8, the default `ChannelInterceptor` for making the `CsrfToken` available with xref:servlet/integrations/websocket.adoc[WebSocket Security] is `CsrfChannelInterceptor`.
`XorCsrfChannelInterceptor` was added to allow opting into CSRF BREACH support.
In Spring Security 6, `XorCsrfChannelInterceptor` is the default `ChannelInterceptor` for making the `CsrfToken` available.
If you configured the `XorCsrfChannelInterceptor` only for the purpose of updating to 6.0, you can remove it completely.

View File

@ -0,0 +1,80 @@
= OAuth 2.0 Migrations
== Validate `typ` Header with `JwtTypeValidator`
If when following the 6.5 preparatory steps you set `validateTypes` to `false`, you can now remove it.
You can also remove explicitly adding `JwtTypeValidator` to the list of defaults.
For example, change this:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.validateTypes(false) <1>
// ... your remaining configuration
.build();
jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
new JwtIssuerValidator(location), JwtTypeValidator.jwt())); <2>
return jwtDecoder;
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun jwtDecoder(): JwtDecoder {
val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
.validateTypes(false) <1>
// ... your remaining configuration
.build()
jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
JwtIssuerValidator(location), JwtTypeValidator.jwt())) <2>
return jwtDecoder
}
----
======
<1> - Switch off Nimbus verifying the `typ`
<2> - Add the default `typ` validator
to this:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
// ... your remaining configuration <1>
.build();
jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(location)); <2>
return jwtDecoder;
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun jwtDecoder(): JwtDecoder {
val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
// ... your remaining configuration
.build()
jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(location)) <2>
return jwtDecoder
}
----
======
<1> - `validateTypes` now defaults to `false`
<2> - `JwtTypeValidator#jwt` is added by all `createDefaultXXX` methods

View File

@ -1,49 +0,0 @@
= Session Management Migrations
The following steps relate to how to finish migrating session management support.
== Require Explicit Saving of SecurityContextRepository
In Spring Security 5, the default behavior is for the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontext[`SecurityContext`] to automatically be saved to the xref:servlet/authentication/persistence.adoc#securitycontextrepository[`SecurityContextRepository`] using the xref:servlet/authentication/persistence.adoc#securitycontextpersistencefilter[`SecurityContextPersistenceFilter`].
Saving must be done just prior to the `HttpServletResponse` being committed and just before `SecurityContextPersistenceFilter`.
Unfortunately, automatic persistence of the `SecurityContext` can surprise users when it is done prior to the request completing (i.e. just prior to committing the `HttpServletResponse`).
It also is complex to keep track of the state to determine if a save is necessary causing unnecessary writes to the `SecurityContextRepository` (i.e. `HttpSession`) at times.
In Spring Security 6, the default behavior is that the xref:servlet/authentication/persistence.adoc#securitycontextholderfilter[`SecurityContextHolderFilter`] will only read the `SecurityContext` from `SecurityContextRepository` and populate it in the `SecurityContextHolder`.
Users now must explicitly save the `SecurityContext` with the `SecurityContextRepository` if they want the `SecurityContext` to persist between requests.
This removes ambiguity and improves performance by only requiring writing to the `SecurityContextRepository` (i.e. `HttpSession`) when it is necessary.
[NOTE]
====
Saving the context is also needed when clearing it out, for example during logout. Refer to this section to xref:servlet/authentication/session-management.adoc#properly-clearing-authentication[know more about that].
====
If you are explicitly opting into Spring Security 6's new defaults, the following configuration can be removed to accept the Spring Security 6 defaults.
include::partial$servlet/architecture/security-context-explicit.adoc[]
== Multiple SecurityContextRepository
In Spring Security 5, the default xref:servlet/authentication/persistence.adoc#securitycontextrepository[`SecurityContextRepository`] was `HttpSessionSecurityContextRepository`.
In Spring Security 6, the default `SecurityContextRepository` is `DelegatingSecurityContextRepository`.
If you configured the `SecurityContextRepository` only for the purpose of updating to 6.0, you can remove it completely.
== Deprecation in SecurityContextRepository
There are no further migration steps for this deprecation.
[[requestcache-query-optimization]]
== Optimize Querying of `RequestCache`
In Spring Security 5, the default behavior is to query the xref:servlet/architecture.adoc#savedrequests[saved request] on every request.
This means that in a typical setup, that in order to use the xref:servlet/architecture.adoc#requestcache[`RequestCache`] the `HttpSession` is queried on every request.
In Spring Security 6, the default is that `RequestCache` will only be queried for a cached request if the HTTP parameter `continue` is defined.
This allows Spring Security to avoid unnecessarily reading the `HttpSession` with the `RequestCache`.
In Spring Security 5 the default is to use `HttpSessionRequestCache` which will be queried for a cached request on every request.
If you are not overriding the defaults (i.e. using `NullRequestCache`), then the following configuration can be used to explicitly opt into the Spring Security 6 behavior in Spring Security 5.8:
include::partial$servlet/architecture/request-cache-continue.adoc[]