diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 09130e387e..595e9a4531 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -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] diff --git a/docs/modules/ROOT/pages/migration-7/authentication.adoc b/docs/modules/ROOT/pages/migration-7/authentication.adoc deleted file mode 100644 index 9c5407ae00..0000000000 --- a/docs/modules/ROOT/pages/migration-7/authentication.adoc +++ /dev/null @@ -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) -} ----- -====== diff --git a/docs/modules/ROOT/pages/migration-7/authorization.adoc b/docs/modules/ROOT/pages/migration-7/authorization.adoc deleted file mode 100644 index 031c8a8bfb..0000000000 --- a/docs/modules/ROOT/pages/migration-7/authorization.adoc +++ /dev/null @@ -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]. diff --git a/docs/modules/ROOT/pages/migration-7/configuration.adoc b/docs/modules/ROOT/pages/migration-7/configuration.adoc deleted file mode 100644 index 0a06694f95..0000000000 --- a/docs/modules/ROOT/pages/migration-7/configuration.adoc +++ /dev/null @@ -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]. diff --git a/docs/modules/ROOT/pages/migration-7/ldap.adoc b/docs/modules/ROOT/pages/migration-7/ldap.adoc deleted file mode 100644 index 3bef91f9ac..0000000000 --- a/docs/modules/ROOT/pages/migration-7/ldap.adoc +++ /dev/null @@ -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. diff --git a/docs/modules/ROOT/pages/migration-7/oauth2.adoc b/docs/modules/ROOT/pages/migration-7/oauth2.adoc deleted file mode 100644 index 1c3b9b43e2..0000000000 --- a/docs/modules/ROOT/pages/migration-7/oauth2.adoc +++ /dev/null @@ -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. diff --git a/docs/modules/ROOT/pages/migration-7/saml2.adoc b/docs/modules/ROOT/pages/migration-7/saml2.adoc deleted file mode 100644 index eed236a64b..0000000000 --- a/docs/modules/ROOT/pages/migration-7/saml2.adoc +++ /dev/null @@ -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() { - @Override - public Saml2WebSsoAuthenticationFilter postProcess(Saml2WebSsoAuthenticationFilter filter) { - filter.setContinueChainWhenNoRelyingPartyRegistrationFound(true); - return filter; - } - }) - ) ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -http { - saml2Login { } - withObjectPostProcessor( - object : ObjectPostProcessor() { - override fun postProcess(filter: Saml2WebSsoAuthenticationFilter): Saml2WebSsoAuthenticationFilter { - filter.setContinueChainWhenNoRelyingPartyRegistrationFound(true) - return filter - } - }) -} ----- - -Xml:: -+ -[source,xml,role="secondary"] ----- - ----- -====== - -== Validate Response After Validating Assertions - -In Spring Security 6, the order of authenticating a `` 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) ----- -====== diff --git a/docs/modules/ROOT/pages/migration-7/web.adoc b/docs/modules/ROOT/pages/migration-7/web.adoc deleted file mode 100644 index 467f2663e8..0000000000 --- a/docs/modules/ROOT/pages/migration-7/web.adoc +++ /dev/null @@ -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"] ----- - - - ----- -====== - -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"] ----- - - - - - - - ----- -====== - -== 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"] ----- - - ----- -====== - -[[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"] ----- - ----- -====== - -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"] ----- - ----- -====== - -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 <> 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"] ----- - - - - ----- -====== - -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"] ----- - - - - - - - - - ----- -====== - -[TIP] -===== -If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance. -===== diff --git a/docs/modules/ROOT/pages/migration-7/index.adoc b/docs/modules/ROOT/pages/migration-8/index.adoc similarity index 52% rename from docs/modules/ROOT/pages/migration-7/index.adoc rename to docs/modules/ROOT/pages/migration-8/index.adoc index 9cdb6dfda5..fe4b8cba89 100644 --- a/docs/modules/ROOT/pages/migration-7/index.adoc +++ b/docs/modules/ROOT/pages/migration-8/index.adoc @@ -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. diff --git a/docs/modules/ROOT/pages/migration/index.adoc b/docs/modules/ROOT/pages/migration/index.adoc index db1d8d1333..4ad6c991df 100644 --- a/docs/modules/ROOT/pages/migration/index.adoc +++ b/docs/modules/ROOT/pages/migration/index.adoc @@ -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 diff --git a/docs/modules/ROOT/pages/migration/reactive.adoc b/docs/modules/ROOT/pages/migration/reactive.adoc index 370e52262f..17d33ff586 100644 --- a/docs/modules/ROOT/pages/migration/reactive.adoc +++ b/docs/modules/ROOT/pages/migration/reactive.adoc @@ -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. -==== diff --git a/docs/modules/ROOT/pages/migration/servlet/authentication.adoc b/docs/modules/ROOT/pages/migration/servlet/authentication.adoc deleted file mode 100644 index 3db94cf7a6..0000000000 --- a/docs/modules/ROOT/pages/migration/servlet/authentication.adoc +++ /dev/null @@ -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"] ----- - - - - - - - - ----- -====== - -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"] ----- - - - - - - - - ----- -====== - -[[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"] ----- - - - - - - - - - ----- -====== - -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"] ----- - - - - - - - ----- -====== - -== 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. diff --git a/docs/modules/ROOT/pages/migration/servlet/authorization.adoc b/docs/modules/ROOT/pages/migration/servlet/authorization.adoc deleted file mode 100644 index 0f60a2f4c1..0000000000 --- a/docs/modules/ROOT/pages/migration/servlet/authorization.adoc +++ /dev/null @@ -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, `` 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"] ----- - ----- -====== - -changes to: - -[tabs] -====== -Xml:: -+ -[source,xml,role="primary"] ----- - ----- -====== - -There are no further migrations steps for Java or Kotlin for this feature. - -== Use `AuthorizationManager` for Request Security - -In 6.0, `` 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"] ----- - ----- -====== - -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"] ----- - ----- -====== - -[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]. diff --git a/docs/modules/ROOT/pages/migration/servlet/exploits.adoc b/docs/modules/ROOT/pages/migration/servlet/exploits.adoc deleted file mode 100644 index bddafec6c2..0000000000 --- a/docs/modules/ROOT/pages/migration/servlet/exploits.adoc +++ /dev/null @@ -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. diff --git a/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc b/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc new file mode 100644 index 0000000000..3caeec4133 --- /dev/null +++ b/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc @@ -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 diff --git a/docs/modules/ROOT/pages/migration/servlet/session-management.adoc b/docs/modules/ROOT/pages/migration/servlet/session-management.adoc deleted file mode 100644 index c7409b9e07..0000000000 --- a/docs/modules/ROOT/pages/migration/servlet/session-management.adoc +++ /dev/null @@ -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[]